Beispiel #1
0
int EDIT_TOOL::Remove( const TOOL_EVENT& aEvent )
{
    const SELECTION& selection = m_selectionTool->GetSelection();

    if( !hoverSelection( selection ) )
        return 0;

    // Get a copy of the selected items set
    PICKED_ITEMS_LIST selectedItems = selection.items;
    PCB_BASE_FRAME* editFrame = getEditFrame<PCB_BASE_FRAME>();

    // As we are about to remove items, they have to be removed from the selection first
    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );

    // Save them
    for( unsigned int i = 0; i < selectedItems.GetCount(); ++i )
        selectedItems.SetPickedItemStatus( UR_DELETED, i );

    editFrame->OnModify();
    editFrame->SaveCopyInUndoList( selectedItems, UR_DELETED );

    // And now remove
    for( unsigned int i = 0; i < selectedItems.GetCount(); ++i )
        remove( static_cast<BOARD_ITEM*>( selectedItems.GetPickedItem( i ) ) );

    getModel<BOARD>()->GetRatsnest()->Recalculate();

    return 0;
}
void DuplicateItemsInList( SCH_SCREEN* screen, PICKED_ITEMS_LIST& aItemsList,
                           const wxPoint& aMoveVector )
{
    SCH_ITEM* newitem;

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

    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        newitem = DuplicateStruct( (SCH_ITEM*) aItemsList.GetPickedItem( ii ) );
        aItemsList.SetPickedItem( newitem, ii );
        aItemsList.SetPickedItemStatus( UR_NEW, ii );
        {
            switch( newitem->Type() )
            {
            case SCH_JUNCTION_T:
            case SCH_LINE_T:
            case SCH_BUS_BUS_ENTRY_T:
            case SCH_BUS_WIRE_ENTRY_T:
            case SCH_TEXT_T:
            case SCH_LABEL_T:
            case SCH_GLOBAL_LABEL_T:
            case SCH_HIERARCHICAL_LABEL_T:
            case SCH_SHEET_PIN_T:
            case SCH_MARKER_T:
            case SCH_NO_CONNECT_T:
            default:
                break;

            case SCH_SHEET_T:
            {
                SCH_SHEET* sheet = (SCH_SHEET*) newitem;
                sheet->SetTimeStamp( GetNewTimeStamp() );
                break;
            }

            case SCH_COMPONENT_T:
                ( (SCH_COMPONENT*) newitem )->SetTimeStamp( GetNewTimeStamp() );
                ( (SCH_COMPONENT*) newitem )->ClearAnnotation( NULL );
                break;
            }

            SetSchItemParent( newitem, screen );
            screen->Append( newitem );
        }
    }

    MoveItemsInList( aItemsList, aMoveVector );
}
/**
 * Function DeleteItemsInList
 * delete schematic items in aItemsList
 * deleted items are put in undo list
 */
void DeleteItemsInList( EDA_DRAW_PANEL* panel, PICKED_ITEMS_LIST& aItemsList )
{
    SCH_SCREEN*        screen = (SCH_SCREEN*) panel->GetScreen();
    SCH_EDIT_FRAME*    frame  = (SCH_EDIT_FRAME*) panel->GetParent();
    PICKED_ITEMS_LIST  itemsList;

    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
        ITEM_PICKER itemWrapper( item, UR_DELETED );

        if( item->Type() == SCH_SHEET_PIN_T )
        {
            /* this item is depending on a sheet, and is not in global list */
            wxMessageBox( wxT( "DeleteItemsInList() err: unexpected SCH_SHEET_PIN_T" ) );
        }
        else
        {
            screen->Remove( item );

            /* Unlink the structure */
            itemsList.PushItem( itemWrapper );
        }
    }

    frame->SaveCopyInUndoList( itemsList, UR_DELETED );
}
Beispiel #4
0
void PCB_EDIT_FRAME::Block_Delete()
{
    OnModify();
    SetCurItem( NULL );

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

    // unlink items and clear flags
    for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ )
    {
        BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
        itemsList->SetPickedItemStatus( UR_DELETED, ii );
        GetBoard()->GetConnectivity()->Remove( item );

        switch( item->Type() )
        {
        case PCB_MODULE_T:
        {
            MODULE* module = (MODULE*) item;
            module->ClearFlags();
            module->UnLink();
            m_Pcb->m_Status_Pcb = 0;
        }
        break;

        case PCB_ZONE_AREA_T:     // a zone area
            m_Pcb->Remove( item );
            break;

        case PCB_LINE_T:          // a segment not on copper layers
        case PCB_TEXT_T:          // a text on a layer
        case PCB_TRACE_T:         // a track segment (segment on a copper layer)
        case PCB_VIA_T:           // a via (like track segment on a copper layer)
        case PCB_DIMENSION_T:     // a dimension (graphic item)
        case PCB_TARGET_T:        // a target (graphic item)
            item->UnLink();
            break;

        // These items are deleted, but not put in undo list
        case PCB_MARKER_T:                  // a marker used to show something
        case PCB_ZONE_T:                     // SEG_ZONE items are now deprecated
            item->UnLink();
            itemsList->RemovePicker( ii );
            ii--;
            item->DeleteStructure();
            break;

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

    SaveCopyInUndoList( *itemsList, UR_DELETED );

    Compile_Ratsnest( NULL, true );
    m_canvas->Refresh( true );
}
Beispiel #5
0
void PCB_EDIT_FRAME::Block_Flip()
{
#define INVERT( pos ) (pos) = center.y - ( (pos) - center.y )
    wxPoint memo;
    wxPoint center; // Position of the axis for inversion of all elements

    OnModify();

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

    memo = GetCrossHairPosition();

    center = GetScreen()->m_BlockLocate.Centre();

    for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ )
    {
        BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
        wxASSERT( item );
        itemsList->SetPickedItemStatus( UR_FLIPPED, ii );
        item->Flip( center );

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

        // Move and rotate the track segments
        case PCB_TRACE_T:       // a track segment (segment on a copper layer)
        case PCB_VIA_T:         // a via (like 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_Flip( ) error: unexpected type" ) );
            break;
        }
    }

    SaveCopyInUndoList( *itemsList, UR_FLIPPED, center );
    Compile_Ratsnest( NULL, true );
    m_canvas->Refresh( true );
}
void MoveItemsInList( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMoveVector )
{
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
        item->Move( aMoveVector );
    }
}
Beispiel #7
0
void PCB_EDIT_FRAME::Block_Rotate()
{
    wxPoint oldpos;
    wxPoint centre;         // rotation cent-re for the rotation transform
    int     rotAngle = 900; // rotation angle in 0.1 deg.

    oldpos = GetScreen()->GetCrossHairPosition();
    centre = GetScreen()->m_BlockLocate.Centre();

    OnModify();

    PICKED_ITEMS_LIST* itemsList = &GetScreen()->m_BlockLocate.m_ItemsSelection;
    itemsList->m_Status = UR_ROTATED;

    for( unsigned ii = 0; ii < itemsList->GetCount(); ii++ )
    {
        BOARD_ITEM* item = (BOARD_ITEM*) itemsList->GetPickedItem( ii );
        wxASSERT( item );
        itemsList->SetPickedItemStatus( UR_ROTATED, ii );
        item->Rotate( centre, rotAngle );

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

        /* Move and rotate the track segments */
        case PCB_TRACE_T:       // a track segment (segment on a copper layer)
        case PCB_VIA_T:         // a via (like 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_Rotate( ) error: unexpected type" ) );
            break;
        }
    }

    SaveCopyInUndoList( *itemsList, UR_ROTATED, centre );

    Compile_Ratsnest( NULL, true );
    m_canvas->Refresh( true );
}
void MirrorX( PICKED_ITEMS_LIST& aItemsList, const wxPoint& aMirrorPoint )
{
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
        item->MirrorX( aMirrorPoint.y );      // Place it in its new position.
        item->ClearFlags();
    }
}
void RotateListOfItems( PICKED_ITEMS_LIST& aItemsList, const wxPoint& rotationPoint )
{
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
        item->Rotate( rotationPoint );      // Place it in its new position.
        item->ClearFlags();
    }
}
void PCB_EDIT_FRAME::Delete_Drawings_All_Layer( LAYER_ID aLayer )
{
    if( IsCopperLayer( aLayer ) )
    {
        DisplayError( this, _( "Copper layer global delete not allowed!" ) );
        return;
    }

    wxString msg = wxString::Format(
        _( "Delete everything on layer %s?" ),
        GetChars( GetBoard()->GetLayerName( aLayer ) ) );

    if( !IsOK( this, msg ) )
        return;

    PICKED_ITEMS_LIST   pickList;
    ITEM_PICKER         picker( NULL, UR_DELETED );
    BOARD_ITEM*         PtNext;

    for( BOARD_ITEM* item = GetBoard()->m_Drawings;  item;  item = PtNext )
    {
        PtNext = item->Next();

        switch( item->Type() )
        {
        case PCB_LINE_T:
        case PCB_TEXT_T:
        case PCB_DIMENSION_T:
        case PCB_TARGET_T:
            if( item->GetLayer() == aLayer )
            {
                item->UnLink();
                picker.SetItem( item );
                pickList.PushItem( picker );
            }

            break;

        default:
        {
            wxString msg;
            msg.Printf( wxT("Delete_Drawings_All_Layer() error: unknown type %d"),
                        item->Type() );
            wxMessageBox( msg );
            break;
        }
        }
    }

    if( pickList.GetCount() )
    {
        OnModify();
        SaveCopyInUndoList(pickList, UR_DELETED);
    }
}
/*
 * Function SaveCopyInUndoList
 * Create a copy of the current board item, and put it in the undo list.
 *
 *  aCommandType =
 *      UR_CHANGED
 *      UR_NEW
 *      UR_DELETED
 *      UR_MOVED
 *      UR_FLIPPED
 *      UR_ROTATED
 */
void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM*    aItem,
                                         UNDO_REDO_T    aCommandType,
                                         const wxPoint& aTransformPoint )
{
    if( aItem == NULL )     // Nothing to save
        return;

    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;

    ITEM_PICKER itemWrapper( aItem, aCommandType );

    switch( aCommandType )
    {
    case UR_CHANGED:                        // Create a copy of item
        if( itemWrapper.GetLink() == NULL ) // When not null, the copy is already done
            itemWrapper.SetLink( aItem->Clone() );
        commandToUndo->PushItem( itemWrapper );
        break;

    case UR_NEW:
    case UR_DELETED:
#ifdef USE_WX_OVERLAY
        m_canvas->Refresh();
#endif
    case UR_MOVED:
    case UR_FLIPPED:
    case UR_ROTATED:
    case UR_ROTATED_CLOCKWISE:
        commandToUndo->PushItem( itemWrapper );
        break;

    default:
    {
        wxString msg;
        msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), aCommandType );
        wxMessageBox( msg );
    }
    break;
    }

    if( commandToUndo->GetCount() )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after new save there is no redo to do */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else
    {
        delete commandToUndo;
    }
}
Beispiel #12
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 );
}
Beispiel #13
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 );
}
void SCH_EDIT_FRAME::CheckListConnections( PICKED_ITEMS_LIST& aItemsList, bool aAppend )
{
    std::vector< wxPoint > pts;
    std::vector< wxPoint > connections;

    GetSchematicConnections( connections );
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
        std::vector< wxPoint > new_pts;

        if( !item->IsConnectable() )
            continue;

        item->GetConnectionPoints( new_pts );
        pts.insert( pts.end(), new_pts.begin(), new_pts.end() );

        // If the item is a line, we also add any connection points from the rest of the schematic
        // that terminate on the line after it is moved.
        if( item->Type() == SCH_LINE_T )
        {
            SCH_LINE* line = (SCH_LINE*) item;
            for( auto i : connections )
                if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), i ) )
                    pts.push_back( i );
        }
        else
        {
            // Clean up any wires that short non-wire connections in the list
            for( auto point = new_pts.begin(); point != new_pts.end(); point++ )
            {
                for( auto second_point = point + 1; second_point != new_pts.end(); second_point++ )
                {
                    aAppend |= TrimWire( *point, *second_point, aAppend );
                }
            }
        }
    }

    // We always have some overlapping connection points.  Drop duplicates here
    std::sort( pts.begin(), pts.end(),
            []( const wxPoint& a, const wxPoint& b ) -> bool
            { return a.x < b.x || (a.x == b.x && a.y < b.y); } );
    pts.erase( unique( pts.begin(), pts.end() ), pts.end() );

    for( auto point : pts )
    {
        if( GetScreen()->IsJunctionNeeded( point, true ) )
        {
            AddJunction( point, aAppend );
            aAppend = true;
        }
    }
}
Beispiel #15
0
void SCH_EDIT_FRAME::SaveCopyInUndoList( SCH_ITEM*      aItem,
                                         UNDO_REDO_T    aCommandType,
                                         const wxPoint& aTransformPoint )
{
    /* Does not save a null item or a UR_WIRE_IMAGE command type.  UR_WIRE_IMAGE commands
     * are handled by the overloaded version of SaveCopyInUndoList that takes a reference
     * to a PICKED_ITEMS_LIST.
     */
    if( aItem == NULL || aCommandType == UR_WIRE_IMAGE )
        return;

    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
    commandToUndo->m_TransformPoint = aTransformPoint;

    ITEM_PICKER itemWrapper( aItem, aCommandType );

    if( aItem )
        itemWrapper.SetFlags( aItem->GetFlags() );

    switch( aCommandType )
    {
    case UR_CHANGED:            /* Create a copy of item */
        itemWrapper.SetLink( DuplicateStruct( aItem, true ) );
        commandToUndo->PushItem( itemWrapper );
        break;

    case UR_NEW:
    case UR_DELETED:
    case UR_ROTATED:
    case UR_MOVED:
        commandToUndo->PushItem( itemWrapper );
        break;

    default:
        wxFAIL_MSG( wxString::Format( wxT( "SaveCopyInUndoList() error (unknown code %X)" ),
                                      aCommandType ) );
        break;
    }

    if( commandToUndo->GetCount() )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after new save there is no redo to do */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else
    {
        delete commandToUndo;
    }
}
Beispiel #16
0
void PCB_EDIT_FRAME::Edit_Track_Width( wxDC* aDC, TRACK* aTrackSegment )
{
    /* Modify a full track (a trace) width (using DRC control).
     * a full track is the set of track segments between 2 nodes: pads or a node that has
     * more than 2 segments connected
     * aDC = the curred device context (can be NULL)
     * aTrackSegment = a via or a track belonging to the trace to change
     */
    TRACK* pt_track;
    int    nb_segm;

    if( aTrackSegment == NULL )
        return;

    pt_track = GetBoard()->MarkTrace( GetBoard()->m_Track, aTrackSegment, &nb_segm,
                                      NULL, NULL, true );

    PICKED_ITEMS_LIST itemsListPicker;
    bool change = false;

    for( int ii = 0; ii < nb_segm; ii++, pt_track = pt_track->Next() )
    {
        pt_track->SetState( BUSY, false );

        if( !SetTrackSegmentWidth( pt_track, &itemsListPicker, false ) )
            change = true;
    }

    if( !change )
        return;

    // Some segment have changed: redraw them and save in undo list
    if( aDC )
    {
        m_canvas->CrossHairOff( aDC );                     // Erase cursor shape

        for( unsigned ii = 0; ii < itemsListPicker.GetCount(); ii++ )
        {
            TRACK* segm = (TRACK*) itemsListPicker.GetPickedItemLink( ii );
            segm->Draw( m_canvas, aDC, GR_XOR );            // Erase old track shape
            segm = (TRACK*) itemsListPicker.GetPickedItem( ii );
            segm->Draw( m_canvas, aDC, GR_OR );             // Display new track shape

// fixme: commit!
//          segm->ViewUpdate( KIGFX::VIEW_ITEM::GEOMETRY );
        }

        m_canvas->CrossHairOn( aDC );                   // Display cursor shape
    }

    SaveCopyInUndoList( itemsListPicker, UR_CHANGED );
}
void FOOTPRINT_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
                                               UNDO_REDO_T        aTypeCommand,
                                               const wxPoint&     aTransformPoint )
{
    assert( aItemsList.GetPickedItem( 0 )->GetParent()->Type() == PCB_MODULE_T );
    MODULE* owner = static_cast<MODULE*>( aItemsList.GetPickedItem( 0 )->GetParent() );

#ifndef NDEBUG
    // All items should have the same parent (MODULE) to make undo/redo entry valid
    for( unsigned int i = 0; i < aItemsList.GetCount(); ++i )
        assert( aItemsList.GetPickedItem( i )->GetParent() == owner );
#endif /* not NDEBUG */

    SaveCopyInUndoList( owner, aTypeCommand, aTransformPoint );
}
void SCH_EDIT_FRAME::DeleteItemsInList( PICKED_ITEMS_LIST& aItemsList, bool aAppend )
{
    PICKED_ITEMS_LIST  itemsList;

    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) aItemsList.GetPickedItem( ii );
        ITEM_PICKER itemWrapper( item, UR_DELETED );

        if( item->GetFlags() & STRUCT_DELETED )
            continue;

        DeleteItem( item, aAppend );
        aAppend = true;
    }

    GetScreen()->ClearDrawingState();
}
/**
 * Function Edit_Track_Width
 * Modify a full track width (using DRC control).
 * a full track is the set of track segments between 2 ends: pads or a point that has
 * more than 2 segments ends connected
 * @param aDC = the curred device context (can be NULL)
 * @param aTrackSegment = a segment or via on the track to change
 */
void PCB_EDIT_FRAME::Edit_Track_Width( wxDC* aDC, TRACK* aTrackSegment )
{
    TRACK* pt_track;
    int    nb_segm;

    if( aTrackSegment == NULL )
        return;

    pt_track = GetBoard()->MarkTrace( aTrackSegment, &nb_segm, NULL, NULL, true );

    PICKED_ITEMS_LIST itemsListPicker;
    bool change = false;

    for( int ii = 0; ii < nb_segm; ii++, pt_track = pt_track->Next() )
    {
        pt_track->SetState( BUSY, false );

        if( SetTrackSegmentWidth( pt_track, &itemsListPicker, false ) )
            change = true;
    }

    if( !change )
        return;

    // Some segment have changed: redraw them and save in undo list
    if( aDC )
    {
        m_canvas->CrossHairOff( aDC );                     // Erase cursor shape

        for( unsigned ii = 0; ii < itemsListPicker.GetCount(); ii++ )
        {
            TRACK* segm = (TRACK*) itemsListPicker.GetPickedItemLink( ii );
            segm->Draw( m_canvas, aDC, GR_XOR );            // Erase old track shape
            segm = (TRACK*) itemsListPicker.GetPickedItem( ii );
            segm->Draw( m_canvas, aDC, GR_OR );             // Display new track shape
        }

        m_canvas->CrossHairOn( aDC );                   // Display cursor shape
    }

    SaveCopyInUndoList( itemsListPicker, UR_CHANGED );
}
Beispiel #20
0
void SCH_EDIT_FRAME::copyBlockItems( PICKED_ITEMS_LIST& aItemsList )
{
    m_blockItems.ClearListAndDeleteItems();   // delete previous saved list, if exists

    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        // Clear m_Flag member of selected items:
        aItemsList.GetPickedItem( ii )->ClearFlags();
        /* Make a copy of the original picked item. */
        SCH_ITEM* copy = DuplicateStruct( (SCH_ITEM*) aItemsList.GetPickedItem( ii ) );
        copy->SetParent( NULL );

        // In list the wrapper is owner of the schematic item, we can use the UR_DELETED
        // status for the picker because pickers with this status are owner of the picked item
        // (or TODO ?: create a new status like UR_DUPLICATE)
        ITEM_PICKER item( copy, UR_DELETED );

        m_blockItems.PushItem( item );
    }
}
Beispiel #21
0
static void drawPickedItems( EDA_DRAW_PANEL* aPanel, wxDC* aDC, wxPoint aOffset )
{
    PICKED_ITEMS_LIST* itemsList = &aPanel->GetScreen()->m_BlockLocate.GetItems();
    PCB_BASE_FRAME* frame = (PCB_BASE_FRAME*) aPanel->GetParent();

    g_Offset_Module = -aOffset;

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

        switch( item->Type() )
        {
        case PCB_MODULE_T:
            frame->GetBoard()->m_Status_Pcb &= ~RATSNEST_ITEM_LOCAL_OK;
            ((MODULE*) item)->DrawOutlinesWhenMoving( aPanel, aDC, g_Offset_Module );
            break;

        case PCB_LINE_T:
        case PCB_TEXT_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
        case PCB_TARGET_T:
        case PCB_DIMENSION_T:    // Currently markers are not affected by block commands
        case PCB_MARKER_T:
            item->Draw( aPanel, aDC, GR_XOR, aOffset );
            break;

        case PCB_ZONE_AREA_T:
            item->Draw( aPanel, aDC, GR_XOR, aOffset );
            ((ZONE_CONTAINER*) item)->DrawFilledArea( aPanel, aDC, GR_XOR, aOffset );
            break;

        default:
            break;
        }
    }

    g_Offset_Module = wxPoint( 0, 0 );
}
Beispiel #22
0
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
                                         UNDO_REDO_T aTypeCommand, const wxPoint& aTransformPoint )
{
    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;

    // First, filter unnecessary stuff from the list (i.e. for multiple pads / labels modified),
    // take the first occurence of the module (we save copies of modules when one of its subitems
    // is changed).
    for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
    {
        ITEM_PICKER curr_picker = aItemsList.GetItemWrapper(ii);
        BOARD_ITEM* item    = (BOARD_ITEM*) aItemsList.GetPickedItem( ii );

        // For items belonging to modules, we need to save state of the parent module
        if( item->Type() == PCB_MODULE_TEXT_T || item->Type() == PCB_MODULE_EDGE_T
                || item->Type() == PCB_PAD_T )
        {
            // Item to be stored in the undo buffer is the parent module
            item = item->GetParent();
            wxASSERT( item && item->Type() == PCB_MODULE_T );

            if( item == NULL )
                continue;

            // Check if the parent module has already been saved in another entry
            bool found = false;

            for( unsigned j = 0; j < commandToUndo->GetCount(); j++ )
            {
                if( commandToUndo->GetPickedItem( j ) == item && commandToUndo->GetPickedItemStatus( j ) == UR_CHANGED )
                {
                    found = true;
                    break;
                }
            }

            if( !found )
            {
                // Create a clean copy of the parent module
                MODULE* orig = static_cast<MODULE*>( item );
                MODULE* clone = new MODULE( *orig );
                clone->SetParent( GetBoard() );

                // Clear current flags (which can be temporary set by a current edit command)
                for( EDA_ITEM* loc_item = clone->GraphicalItemsList(); loc_item;
                        loc_item = loc_item->Next() )
                    loc_item->ClearFlags();

                for( D_PAD* pad = clone->PadsList(); pad; pad = pad->Next() )
                    pad->ClearFlags();

                clone->Reference().ClearFlags();
                clone->Value().ClearFlags();

                ITEM_PICKER picker( item, UR_CHANGED );
                picker.SetLink( clone );
                commandToUndo->PushItem( picker );

                orig->SetLastEditTime();
            }
            else
            {
                continue;
            }
        }
        else
        {
            // Normal case: all other BOARD_ITEMs, are simply copied to the new list
            commandToUndo->PushItem( curr_picker );
        }
    }

    for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
    {
        BOARD_ITEM* item    = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii );
        UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );

        if( command == UR_UNSPECIFIED )
        {
            command = aTypeCommand;
            commandToUndo->SetPickedItemStatus( command, ii );
        }

        wxASSERT( item );

        switch( command )
        {
        case UR_CHANGED:
        case UR_DRILLORIGIN:
        case UR_GRIDORIGIN:

            /* If needed, create a copy of item, and put in undo list
             * in the picker, as link
             * If this link is not null, the copy is already done
             */
            if( commandToUndo->GetPickedItemLink( ii ) == NULL )
            {
                EDA_ITEM* cloned = item->Clone();
                commandToUndo->SetPickedItemLink( cloned, ii );
            }
            break;

        case UR_MOVED:
        case UR_ROTATED:
        case UR_ROTATED_CLOCKWISE:
        case UR_FLIPPED:
        case UR_NEW:
        case UR_DELETED:
            break;

        default:
        {
            wxLogDebug( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), command );
        }
        break;

        }
    }

    if( commandToUndo->GetCount() )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after a new command one cannot redo a command */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else
    {
        // Should not occur
        wxASSERT( false );
        delete commandToUndo;
    }
}
/**
 * Function UpdateCopyOfZonesList
 * check a pick list to remove zones identical to their copies
 * and set the type of operation in picker (UR_DELETED, UR_CHANGED)
 * if an item is deleted, the initial values are retrievered,
 * because they can have changed in edition
 * @param aPickList = the main pick list
 * @param aAuxiliaryList = the list of deleted or added (new created) items after calculations
 * @param aPcb = the Board
 *
 * aAuxiliaryList is a list of pickers updated by zone algorithms:
 *  This list contains zones which were added or deleted during the zones combine process
 * aPickList :is a list of zones that can be modified (changed or deleted, or not modified)
 *  Typically, this is the list of existing zones on the layer of the edited zone,
 *  before any change.
 *  >> if the picked zone is not changed, it is removed from list
 *  >> if the picked zone was deleted (i.e. not found in board list), the picker is modified:
 *          its status becomes UR_DELETED
 *          the aAuxiliaryList corresponding picker is removed (if not found : set an error)
 *  >> if the picked zone was flagged as UR_NEW, and was after deleted ,
 *  perhaps combined with an other zone  (i.e. not found in board list):
 *          the picker is removed
 *          the zone itself if really deleted
 *          the aAuxiliaryList corresponding picker is removed (if not found : set an error)
 * After aPickList is cleaned, the aAuxiliaryList is read
 *  All pickers flagged UR_NEW are moved to aPickList
 * (the corresponding zones are zone that were created by the zone normalize and combine process,
 * mainly when adding cutout areas, or creating self intersecting contours)
 *  All pickers flagged UR_DELETED are removed, and the coresponding zones actually deleted
 * (the corresponding zones are new zone that were created by the zone normalize process,
 * when creating self intersecting contours, and after combined with an existing zone.
 * At the end of the update process the aAuxiliaryList must be void,
 *  because all pickers created by the combine process
 *  must have been removed (removed for new and deleted zones, or moved in aPickList.)
 * If not an error is set.
 */
void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList,
                            PICKED_ITEMS_LIST& aAuxiliaryList,
                            BOARD*             aPcb )
{
    for( unsigned kk = 0; kk < aPickList.GetCount(); kk++ )
    {
        UNDO_REDO_T  status = aPickList.GetPickedItemStatus( kk );

        ZONE_CONTAINER* ref = (ZONE_CONTAINER*) aPickList.GetPickedItem( kk );

        for( unsigned ii = 0; ; ii++ )  // analyse the main picked list
        {
            ZONE_CONTAINER* zone = aPcb->GetArea( ii );

            if( zone == NULL )
            {
                /* End of list: the stored item is not found:
                 * it must be in aDeletedList:
                 * search it and restore initial values
                 * or
                 * if flagged UR_NEW: remove it definitively
                 */
                if( status == UR_NEW )
                {
                    delete ref;
                    ref = NULL;
                    aPickList.RemovePicker( kk );
                    kk--;
                }
                else
                {
                    ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk );
                    aPickList.SetPickedItemStatus( UR_DELETED, kk );

                    wxASSERT_MSG( zcopy != NULL,
                                  wxT( "UpdateCopyOfZonesList() error: link = NULL" ) );

                    ref->Copy( zcopy );

                    // the copy was deleted; the link does not exists now.
                    aPickList.SetPickedItemLink( NULL, kk );
                    delete zcopy;
                }

                // Remove this item from aAuxiliaryList, mainly for tests purpose
                bool notfound = true;

                for( unsigned nn = 0; nn < aAuxiliaryList.GetCount(); nn++ )
                {
                    if( ref != NULL && aAuxiliaryList.GetPickedItem( nn ) == ref )
                    {
                        aAuxiliaryList.RemovePicker( nn );
                        notfound = false;
                        break;
                    }
                }

                wxASSERT_MSG( notfound != true,
                              wxT( "UpdateCopyOfZonesList() error: item not found in "
                                   "aAuxiliaryList" ) );
                break;
            }

            if( zone == ref )      // picked zone found
            {
                if( aPickList.GetPickedItemStatus( kk ) != UR_NEW )
                {
                    ZONE_CONTAINER* zcopy = (ZONE_CONTAINER*) aPickList.GetPickedItemLink( kk );

                    if( zone->IsSame( *zcopy ) )    // Remove picked, because no changes
                    {
                        delete zcopy;               // Delete copy
                        aPickList.RemovePicker( kk );
                        kk--;
                    }
                }

                break;
            }
        }
    }

    // Add new zones in main pick list, and remove pickers from Auxiliary List
    for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); )
    {
        if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_NEW )
        {
            ITEM_PICKER picker = aAuxiliaryList.GetItemWrapper( ii );
            aPickList.PushItem( picker );
            aAuxiliaryList.RemovePicker( ii );
        }
        else if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_DELETED )
        {
            delete aAuxiliaryList.GetPickedItemLink( ii );
            aAuxiliaryList.RemovePicker( ii );
        }
        else
            ii++;
    }

    // Should not occur:
    wxASSERT_MSG( aAuxiliaryList.GetCount() == 0,
                  wxT( "UpdateCopyOfZonesList() error: aAuxiliaryList not empty." ) );
}
int PCB_EDITOR_CONTROL::ZoneMerge( const TOOL_EVENT& aEvent )
{
    SELECTION selection = m_toolMgr->GetTool<SELECTION_TOOL>()->GetSelection();
    BOARD* board = getModel<BOARD>();
    RN_DATA* ratsnest = board->GetRatsnest();
    KIGFX::VIEW* view = getView();

    if( selection.Size() < 2 )
        return 0;

    PICKED_ITEMS_LIST changes;
    int netcode = -1;

    // Loop through all combinations
    for( int ia1 = 0; ia1 < selection.Size() - 1; ++ia1 )
    {
        ZONE_CONTAINER* curr_area = dynamic_cast<ZONE_CONTAINER*>( selection.Item<EDA_ITEM>( ia1 ) );

        if( !curr_area )
            continue;

        netcode = curr_area->GetNetCode();

        EDA_RECT b1 = curr_area->Outline()->GetBoundingBox();
        bool mod_ia1 = false;

        for( int ia2 = selection.Size() - 1; ia2 > ia1; --ia2 )
        {
            ZONE_CONTAINER* area2 = dynamic_cast<ZONE_CONTAINER*>( selection.Item<EDA_ITEM>( ia2 ) );

            if( !area2 )
                continue;

            if( area2->GetNetCode() != netcode )
                continue;

            if( curr_area->GetPriority() != area2->GetPriority() )
                continue;

            if( curr_area->GetIsKeepout() != area2->GetIsKeepout() )
                continue;

            if( curr_area->GetLayer() != area2->GetLayer() )
                continue;

            EDA_RECT b2 = area2->Outline()->GetBoundingBox();

            if( b1.Intersects( b2 ) )
            {
                EDA_ITEM* backup = curr_area->Clone();
                bool ret = board->TestAreaIntersection( curr_area, area2 );

                if( ret && board->CombineAreas( &changes, curr_area, area2 ) )
                {
                    mod_ia1 = true;
                    selection.items.RemovePicker( ia2 );

                    ITEM_PICKER picker( curr_area, UR_CHANGED );
                    picker.SetLink( backup );
                    changes.PushItem( picker );
                }
                else
                {
                    delete backup;
                }
            }
        }

        if( mod_ia1 )
            --ia1;     // if modified, we need to check it again
    }

    m_toolMgr->RunAction( COMMON_ACTIONS::selectionClear, true );
    m_frame->SaveCopyInUndoList( changes, UR_UNSPECIFIED );

    for( unsigned i = 0; i < changes.GetCount(); ++i )
    {
        ITEM_PICKER picker = changes.GetItemWrapper( i );
        BOARD_ITEM* item = static_cast<BOARD_ITEM*>( picker.GetItem() );

        if( picker.GetStatus() == UR_DELETED )
        {
            view->Remove( item );
            ratsnest->Remove( item );
        }
        else if( picker.GetStatus() == UR_CHANGED )
        {
            item->ViewUpdate( KIGFX::VIEW_ITEM::ALL );
            m_toolMgr->RunAction( COMMON_ACTIONS::selectItem, true, item );
        }
    }

    return 0;
}
void SCH_SCREEN::SelectBlockItems()
{
    PICKED_ITEMS_LIST* pickedlist = &m_BlockLocate.GetItems();

    if( pickedlist->GetCount() == 0 )
        return;

    ClearDrawingState();

    for( unsigned ii = 0; ii < pickedlist->GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) pickedlist->GetPickedItem( ii );
        item->SetFlags( SELECTED );
    }

    if( !m_BlockLocate.IsDragging() )
        return;

    // Select all the items in the screen connected to the items in the block.
    // be sure end lines that are on the block limits are seen inside this block
    m_BlockLocate.Inflate( 1 );
    unsigned last_select_id = pickedlist->GetCount();

    for( unsigned ii = 0; ii < last_select_id; ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*)pickedlist->GetPickedItem( ii );
        item->SetFlags( IS_DRAGGED );

        if( item->Type() == SCH_LINE_T )
        {
            item->IsSelectStateChanged( m_BlockLocate );

            if( !item->IsSelected() )
            {   // This is a special case:
                // this selected wire has no ends in block.
                // But it was selected (because it intersects the selecting area),
                // so we must keep it selected and select items connected to it
                // Note: an other option could be: remove it from drag list
                item->SetFlags( SELECTED | SKIP_STRUCT );
                std::vector< wxPoint > connections;
                item->GetConnectionPoints( connections );

                for( size_t i = 0; i < connections.size(); i++ )
                    addConnectedItemsToBlock( connections[i] );
            }

            pickedlist->SetPickerFlags( item->GetFlags(), ii );
        }
        else if( item->IsConnectable() )
        {
            std::vector< wxPoint > connections;

            item->GetConnectionPoints( connections );

            for( size_t jj = 0; jj < connections.size(); jj++ )
                addConnectedItemsToBlock( connections[jj] );
        }
    }

    m_BlockLocate.Inflate( -1 );
}
int SCH_SCREEN::GetConnection( const wxPoint& aPosition, PICKED_ITEMS_LIST& aList,
                               bool aFullConnection )
{
    SCH_ITEM* item;
    EDA_ITEM* tmp;
    EDA_ITEMS list;

    // Clear flags member for all items.
    ClearDrawingState();
    BreakSegmentsOnJunctions();

    if( GetNode( aPosition, list ) == 0 )
        return 0;

    for( size_t i = 0;  i < list.size();  i++ )
    {
        item = (SCH_ITEM*) list[ i ];
        item->SetFlags( SELECTEDNODE | STRUCT_DELETED );

        /* Put this structure in the picked list: */
        ITEM_PICKER picker( item, UR_DELETED );
        aList.PushItem( picker );
    }

    // Mark all wires, junctions, .. connected to the item(s) found.
    if( aFullConnection )
    {
        SCH_LINE* segment;

        for( item = m_drawList.begin(); item; item = item->Next() )
        {
            if( !(item->GetFlags() & SELECTEDNODE) )
                continue;

            if( item->Type() != SCH_LINE_T )
                continue;

            MarkConnections( (SCH_LINE*) item );
        }

        // Search all attached wires (i.e wire with one new dangling end )
        for( item = m_drawList.begin(); item; item = item->Next() )
        {
            bool noconnect = false;

            if( item->GetFlags() & STRUCT_DELETED )
                continue;                                   // Already seen

            if( !(item->GetFlags() & CANDIDATE) )
                continue;                                   // not a candidate

            if( item->Type() != SCH_LINE_T )
                continue;

            item->SetFlags( SKIP_STRUCT );

            segment = (SCH_LINE*) item;

            /* If the wire start point is connected to a wire that was already found
             * and now is not connected, add the wire to the list. */
            for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() )
            {
                // Ensure tmp is a previously deleted segment:
                if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 )
                    continue;

                if( tmp->Type() != SCH_LINE_T )
                    continue;

                SCH_LINE* testSegment = (SCH_LINE*) tmp;

               // Test for segment connected to the previously deleted segment:
                if( testSegment->IsEndPoint( segment->GetStartPoint() ) )
                    break;
            }

            // when tmp != NULL, segment is a new candidate:
            // put it in deleted list if
            // the start point is not connected to an other item (like pin)
            if( tmp && !CountConnectedItems( segment->GetStartPoint(), true ) )
                noconnect = true;

            /* If the wire end point is connected to a wire that has already been found
             * and now is not connected, add the wire to the list. */
            for( tmp = m_drawList.begin(); tmp; tmp = tmp->Next() )
            {
                // Ensure tmp is a previously deleted segment:
                if( ( tmp->GetFlags() & STRUCT_DELETED ) == 0 )
                    continue;

                if( tmp->Type() != SCH_LINE_T )
                    continue;

                SCH_LINE* testSegment = (SCH_LINE*) tmp;

                // Test for segment connected to the previously deleted segment:
                if( testSegment->IsEndPoint( segment->GetEndPoint() ) )
                    break;
            }

            // when tmp != NULL, segment is a new candidate:
            // put it in deleted list if
            // the end point is not connected to an other item (like pin)
            if( tmp && !CountConnectedItems( segment->GetEndPoint(), true ) )
                noconnect = true;

            item->ClearFlags( SKIP_STRUCT );

            if( noconnect )
            {
                item->SetFlags( STRUCT_DELETED );

                ITEM_PICKER picker( item, UR_DELETED );
                aList.PushItem( picker );

                item = m_drawList.begin();
            }
        }

        // Get redundant junctions (junctions which connect < 3 end wires
        // and no pin)
        for( item = m_drawList.begin(); item; item = item->Next() )
        {
            if( item->GetFlags() & STRUCT_DELETED )
                continue;

            if( !(item->GetFlags() & CANDIDATE) )
                continue;

            if( item->Type() != SCH_JUNCTION_T )
                continue;

            SCH_JUNCTION* junction = (SCH_JUNCTION*) item;

            if( CountConnectedItems( junction->GetPosition(), false ) <= 2 )
            {
                item->SetFlags( STRUCT_DELETED );

                ITEM_PICKER picker( item, UR_DELETED );
                aList.PushItem( picker );
            }
        }

        for( item = m_drawList.begin(); item;  item = item->Next() )
        {
            if( item->GetFlags() & STRUCT_DELETED )
                continue;

            if( item->Type() != SCH_LABEL_T )
                continue;

            tmp = GetWireOrBus( ( (SCH_TEXT*) item )->GetPosition() );

            if( tmp && tmp->GetFlags() & STRUCT_DELETED )
            {
                item->SetFlags( STRUCT_DELETED );

                ITEM_PICKER picker( item, UR_DELETED );
                aList.PushItem( picker );
            }
        }
    }

    ClearDrawingState();

    return aList.GetCount();
}
Beispiel #27
0
void SCH_EDIT_FRAME::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList,
                                         UNDO_REDO_T        aTypeCommand,
                                         const wxPoint&     aTransformPoint )
{
    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;
    commandToUndo->m_Status = aTypeCommand;

    // Copy picker list:
    commandToUndo->CopyList( aItemsList );

    // Verify list, and creates data if needed
    for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
    {
        SCH_ITEM* item = (SCH_ITEM*) commandToUndo->GetPickedItem( ii );
        wxASSERT( item );

        UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );

        if( command == UR_UNSPECIFIED )
        {
            command = aTypeCommand;
            commandToUndo->SetPickedItemStatus( command, ii );
        }

        switch( command )
        {
        case UR_CHANGED:        /* Create a copy of item */

            /* If needed, create a copy of item, and put in undo list
             * in the picker, as link
             * If this link is not null, the copy is already done
             */
            if( commandToUndo->GetPickedItemLink( ii ) == NULL )
                commandToUndo->SetPickedItemLink( DuplicateStruct( item, true ), ii );

            wxASSERT( commandToUndo->GetPickedItemLink( ii ) );
            break;

        case UR_MOVED:
        case UR_MIRRORED_Y:
        case UR_MIRRORED_X:
        case UR_ROTATED:
        case UR_NEW:
        case UR_DELETED:
        case UR_EXCHANGE_T:
        case UR_WIRE_IMAGE:
            break;

        default:
            wxFAIL_MSG( wxString::Format( wxT( "Unknown undo/redo command %d" ), command ) );
            break;
        }
    }

    if( commandToUndo->GetCount() || aTypeCommand == UR_WIRE_IMAGE )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after new save there is no redo to do */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else    // Should not occur
    {
        delete commandToUndo;
    }
}
void PCB_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
                                         UNDO_REDO_T        aTypeCommand,
                                         const wxPoint&     aTransformPoint )
{
    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;

    // Copy picker list:
    commandToUndo->CopyList( aItemsList );

    // Verify list, and creates data if needed
    for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
    {
        BOARD_ITEM* item    = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii );

        // For texts belonging to modules, we need to save state of the parent module
        if( item->Type() == PCB_MODULE_TEXT_T )
        {
            item = item->GetParent();
            wxASSERT( item->Type() == PCB_MODULE_T );

            if( item == NULL )
                continue;

            commandToUndo->SetPickedItem( item, ii );
            commandToUndo->SetPickedItemStatus( UR_CHANGED, ii );
        }

        UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );

        if( command == UR_UNSPECIFIED )
        {
            command = aTypeCommand;
            commandToUndo->SetPickedItemStatus( command, ii );
        }

        wxASSERT( item );

        switch( command )
        {
        case UR_CHANGED:

            /* If needed, create a copy of item, and put in undo list
             * in the picker, as link
             * If this link is not null, the copy is already done
             */
            if( commandToUndo->GetPickedItemLink( ii ) == NULL )
                commandToUndo->SetPickedItemLink( item->Clone(), ii );
            break;

        case UR_MOVED:
        case UR_ROTATED:
        case UR_ROTATED_CLOCKWISE:
        case UR_FLIPPED:
        case UR_NEW:
        case UR_DELETED:
            break;

        default:
        {
            wxString msg;
            msg.Printf( wxT( "SaveCopyInUndoList() error (unknown code %X)" ), command );
            wxMessageBox( msg );
        }

        break;

        }
    }

    if( commandToUndo->GetCount() )
    {
        /* Save the copy in undo list */
        GetScreen()->PushCommandToUndoList( commandToUndo );

        /* Clear redo list, because after a new command one cannot redo a command */
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
    else    // Should not occur
    {
        delete commandToUndo;
    }
}
void PCB_EDIT_FRAME::AutoPlaceModule( MODULE* Module, int place_mode, wxDC* DC )
{
    MODULE*             currModule = NULL;
    wxPoint             PosOK;
    wxPoint             memopos;
    int                 error;
    LAYER_ID            lay_tmp_TOP, lay_tmp_BOTTOM;

    // Undo: init list
    PICKED_ITEMS_LIST   newList;

    newList.m_Status = UR_CHANGED;
    ITEM_PICKER         picker( NULL, UR_CHANGED );

    if( GetBoard()->m_Modules == NULL )
        return;

    m_canvas->SetAbortRequest( false );

    switch( place_mode )
    {
    case PLACE_1_MODULE:
        currModule = Module;

        if( currModule == NULL )
            return;

        currModule->SetIsPlaced( false );
        currModule->SetNeedsPlaced( false );
        break;

    case PLACE_OUT_OF_BOARD:
        break;

    case PLACE_ALL:

        if( !IsOK( this, _( "Footprints NOT LOCKED will be moved" ) ) )
            return;

        break;

    case PLACE_INCREMENTAL:

        if( !IsOK( this, _( "Footprints NOT PLACED will be moved" ) ) )
            return;

        break;
    }

    memopos = CurrPosition;
    lay_tmp_BOTTOM  = g_Route_Layer_BOTTOM;
    lay_tmp_TOP     = g_Route_Layer_TOP;

    RoutingMatrix.m_GridRouting = (int) GetScreen()->GetGridSize().x;

    // Ensure Board.m_GridRouting has a reasonable value:
    if( RoutingMatrix.m_GridRouting < Millimeter2iu( 0.25 ) )
        RoutingMatrix.m_GridRouting = Millimeter2iu( 0.25 );

    // Compute module parameters used in auto place
    if( genPlacementRoutingMatrix( GetBoard(), m_messagePanel ) == 0 )
        return;

    int moduleCount = 0;
    Module = GetBoard()->m_Modules;

    for( ; Module != NULL; Module = Module->Next() )
    {
        Module->SetNeedsPlaced( false );

        switch( place_mode )
        {
        case PLACE_1_MODULE:

            if( currModule == Module )
            {
                // Module will be placed, add to undo.
                picker.SetItem( currModule );
                newList.PushItem( picker );
                Module->SetNeedsPlaced( true );
            }

            break;

        case PLACE_OUT_OF_BOARD:
            Module->SetIsPlaced( false );

            if( Module->IsLocked() )
                break;

            if( !RoutingMatrix.m_BrdBox.Contains( Module->GetPosition() ) )
            {
                // Module will be placed, add to undo.
                picker.SetItem( Module );
                newList.PushItem( picker );
                Module->SetNeedsPlaced( true );
            }

            break;

        case PLACE_ALL:
            Module->SetIsPlaced( false );

            if( Module->IsLocked() )
                break;

            // Module will be placed, add to undo.
            picker.SetItem( Module );
            newList.PushItem( picker );
            Module->SetNeedsPlaced( true );
            break;

        case PLACE_INCREMENTAL:

            if( Module->IsLocked() )
            {
                Module->SetIsPlaced( false );
                break;
            }

            if( !Module->NeedsPlaced() )
            {
                // Module will be placed, add to undo.
                picker.SetItem( Module );
                newList.PushItem( picker );
                Module->SetNeedsPlaced( true );
            }

            break;
        }

        if( Module->NeedsPlaced() )    // Erase from screen
        {
            moduleCount++;
            Module->Draw( m_canvas, DC, GR_XOR );
        }
        else
        {
            genModuleOnRoutingMatrix( Module );
        }
    }

    // Undo command: prepare list
    if( newList.GetCount() )
        SaveCopyInUndoList( newList, UR_CHANGED );

    int         cnt = 0;
    wxString    msg;

    while( ( Module = PickModule( this, DC ) ) != NULL )
    {
        // Display some info about activity, module placement can take a while:
        msg.Printf( _( "Place footprint %d of %d" ), cnt, moduleCount );
        SetStatusText( msg );

        double initialOrient = Module->GetOrientation();
        // Display fill area of interest, barriers, penalties.
        drawPlacementRoutingMatrix( GetBoard(), DC );

        error = getOptimalModulePlacement( this, Module, DC );
        double bestScore = MinCout;
        double bestRotation = 0.0;
        int rotAllowed;
        PosOK = CurrPosition;

        if( error == ESC )
            goto end_of_tst;

        // Try orientations 90, 180, 270 degrees from initial orientation
        rotAllowed = Module->GetPlacementCost180();

        if( rotAllowed != 0 )
        {
            Rotate_Module( DC, Module, 1800.0, true );
            error   = getOptimalModulePlacement( this, Module, DC );
            MinCout *= OrientPenality[rotAllowed];

            if( bestScore > MinCout )    // This orientation is better.
            {
                PosOK       = CurrPosition;
                bestScore   = MinCout;
                bestRotation = 1800.0;
            }
            else
            {
                Rotate_Module( DC, Module, initialOrient, false );
            }

            if( error == ESC )
                goto end_of_tst;
        }

        // Determine if the best orientation of a module is 90.
        rotAllowed = Module->GetPlacementCost90();

        if( rotAllowed != 0 )
        {
            Rotate_Module( DC, Module, 900.0, true );
            error   = getOptimalModulePlacement( this, Module, DC );
            MinCout *= OrientPenality[rotAllowed];

            if( bestScore > MinCout )    // This orientation is better.
            {
                PosOK       = CurrPosition;
                bestScore   = MinCout;
                bestRotation = 900.0;
            }
            else
            {
                Rotate_Module( DC, Module, initialOrient, false );
            }

            if( error == ESC )
                goto end_of_tst;
        }

        // Determine if the best orientation of a module is -90.
        if( rotAllowed != 0 )
        {
            Rotate_Module( DC, Module, 2700.0, true );
            error   = getOptimalModulePlacement( this, Module, DC );
            MinCout *= OrientPenality[rotAllowed];

            if( bestScore > MinCout )    // This orientation is better.
            {
                PosOK       = CurrPosition;
                bestScore   = MinCout;
                bestRotation = 2700.0;
            }
            else
            {
                Rotate_Module( DC, Module, initialOrient, false );
            }

            if( error == ESC )
                goto end_of_tst;
        }

end_of_tst:

        if( error == ESC )
            break;

        // Place module.
        CurrPosition = GetCrossHairPosition();
        SetCrossHairPosition( PosOK );

        PlaceModule( Module, DC );

        bestRotation += initialOrient;

        if( bestRotation != Module->GetOrientation() )
            Rotate_Module( DC, Module, bestRotation, false );

        SetCrossHairPosition( CurrPosition );

        Module->CalculateBoundingBox();

        genModuleOnRoutingMatrix( Module );
        Module->SetIsPlaced( true );
        Module->SetNeedsPlaced( false );
    }

    CurrPosition = memopos;

    RoutingMatrix.UnInitRoutingMatrix();

    g_Route_Layer_TOP       = lay_tmp_TOP;
    g_Route_Layer_BOTTOM    = lay_tmp_BOTTOM;

    Module = GetBoard()->m_Modules;

    for( ; Module != NULL; Module = Module->Next() )
    {
        Module->CalculateBoundingBox();
    }

    GetBoard()->m_Status_Pcb = 0;
    Compile_Ratsnest( DC, true );
    m_canvas->ReDraw( DC, true );
}
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;
}