board_undo_redo.cpp 20.1 KB
Newer Older
1 2 3 4
/*************************************************************/
/*  board editor: undo and redo functions for board editor  */
/*************************************************************/

5 6 7
#include <fctsys.h>
#include <class_drawpanel.h>
#include <macros.h>
8

9 10
#include <pcbnew.h>
#include <wxPcbStruct.h>
11

12 13 14 15 16 17 18 19
#include <class_board.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <class_mire.h>
#include <class_module.h>
#include <class_dimension.h>
#include <class_zone.h>
20 21


22 23 24 25 26 27 28 29
/* Functions to undo and redo edit commands.
 *  commmands to undo are stored in CurrentScreen->m_UndoList
 *  commmands to redo are stored in CurrentScreen->m_RedoList
 *
 *  m_UndoList and m_RedoList handle a std::vector of PICKED_ITEMS_LIST
 *  Each PICKED_ITEMS_LIST handle a std::vector of pickers (class ITEM_PICKER),
 *  that store the list of schematic items that are concerned by the command to undo or redo
 *  and is created for each command to undo (handle also a command to redo).
30 31
 *  each picker has a pointer pointing to an item to undo or redo (in fact: deleted, added or
 *  modified),
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
 * and has a pointer to a copy of this item, when this item has been modified
 * (the old values of parameters are therefore saved)
 *
 *  there are 3 cases:
 *  - delete item(s) command
 *  - change item(s) command
 *  - add item(s) command
 *  and 3 cases for block:
 *  - move list of items
 *  - mirror (Y) list of items
 *  - Flip list of items
 *
 *  Undo command
 *  - delete item(s) command:
 *       =>  deleted items are moved in undo list
 *
 *  - change item(s) command
 *      => A copy of item(s) is made (a DrawPickedStruct list of wrappers)
 *      the .m_Link member of each wrapper points the modified item.
 *      the .m_Item member of each wrapper points the old copy of this item.
 *
 *  - add item(s) command
 *      =>A list of item(s) is made. The .m_Item member of each wrapper points the new item.
 *
 *  Redo command
 *  - delete item(s) old command:
 *      => deleted items are moved in EEDrawList list, and in
 *
 *  - change item(s) command
 *      => the copy of item(s) is moved in Undo list
 *
 *  - add item(s) command
64 65
 *      => The list of item(s) is used to create a deleted list in undo list(same as a delete
 *         command)
66
 *
67 68
 *   Some block operations that change items can be undoed without memorise items, just the
 *   coordiantes of the transform:
69 70 71 72 73 74
 *      move list of items (undo/redo is made by moving with the opposite move vector)
 *      mirror (Y) and flip list of items (undo/redo is made by mirror or flip items)
 *      so they are handled specifically.
 *
 */

75

76 77
/**
 * Function TestForExistingItem
78 79 80 81
 * test if aItem exists somewhere in lists of items
 * This is a function unsed by PutDataInPreviousState to be sure an item was not deleted
 * since an undo or redo.
 * This could be possible:
82
 *   - if a call to SaveCopyInUndoList was forgotten in Pcbnew
83
 *   - in zones outlines, when a change in one zone merges this zone with an other
84
 * This function avoids a Pcbnew crash
85 86
 * Before using this function to test existence of items,
 * it must be called with aItem = NULL to prepare the list
87
 * @param aPcb = board to test
88
 * @param aItem = item to find
89
 *              = NULL to build the list of existing items
90
 */
91
static bool TestForExistingItem( BOARD* aPcb, BOARD_ITEM* aItem )
92
{
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    static std::vector<BOARD_ITEM*> itemsList;

    if( aItem == NULL ) // Build list
    {
        // Count items to store in itemsList:
        int icnt = 0;
        BOARD_ITEM* item;

        // Count tracks:
        for( item = aPcb->m_Track; item != NULL; item = item->Next() )
            icnt++;

        // Count modules:
        for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
            icnt++;

        // Count drawings
        for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
            icnt++;

        // Count zones outlines
        icnt +=  aPcb->GetAreaCount();
115

116 117 118
        // Count zones segm (now obsolete):
        for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
             icnt++;
119

120 121 122
        // Build candidate list:
        itemsList.clear();
        itemsList.reserve(icnt);
123

124 125 126 127
        // Store items in list:
        // Append tracks:
        for( item = aPcb->m_Track; item != NULL; item = item->Next() )
            itemsList.push_back( item );
128

129 130 131
        // Append modules:
        for( item = aPcb->m_Modules; item != NULL; item = item->Next() )
            itemsList.push_back( item );
132

133 134 135
        // Append drawings
        for( item = aPcb->m_Drawings; item != NULL; item = item->Next() )
            itemsList.push_back( item );
136

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
        // Append zones outlines
        for( int ii = 0; ii < aPcb->GetAreaCount(); ii++ )
            itemsList.push_back( aPcb->GetArea( ii ) );

        // Append zones segm:
        for( item = aPcb->m_Zone; item != NULL; item = item->Next() )
            itemsList.push_back( item );

        // Sort list
        std::sort( itemsList.begin(), itemsList.end() );
        return false;
    }

    // search in list:
    return std::binary_search( itemsList.begin(), itemsList.end(), aItem );
152
}
153

154

155 156
/**
 * Function SwapData
157 158 159 160 161 162
 * Used in undo / redo command:
 *  swap data between Item and a copy
 *  swapped data is data modified by edition, mainly sizes and texts
 * so ONLY FEW values are swapped
 * @param aItem = the item
 * @param aImage = a copy of the item
163
 */
164
void SwapData( BOARD_ITEM* aItem, BOARD_ITEM* aImage )
165 166 167 168 169 170 171
{
    if( aItem == NULL || aImage == NULL )
    {
        wxMessageBox( wxT( "SwapData error: NULL pointer" ) );
        return;
    }

charras's avatar
charras committed
172
    // Swap layers:
173
    if( aItem->Type() != PCB_MODULE_T && aItem->Type() != PCB_ZONE_AREA_T )
charras's avatar
charras committed
174
    {
175
        // These items have a global swap function.
charras's avatar
charras committed
176 177 178 179 180 181
        int layer, layerimg;
        layer    = aItem->GetLayer();
        layerimg = aImage->GetLayer();
        aItem->SetLayer( layerimg );
        aImage->SetLayer( layer );
    }
182

183 184
    switch( aItem->Type() )
    {
185
    case PCB_MODULE_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
186
        {
187
            MODULE* tmp = (MODULE*) aImage->Clone();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
188 189 190 191 192
            ( (MODULE*) aImage )->Copy( (MODULE*) aItem );
            ( (MODULE*) aItem )->Copy( tmp );
            delete tmp;
        }
        break;
193

194
    case PCB_ZONE_AREA_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
195
        {
196
            ZONE_CONTAINER* tmp = (ZONE_CONTAINER*) aImage->Clone();
Dick Hollenbeck's avatar
Dick Hollenbeck committed
197 198 199 200 201
            ( (ZONE_CONTAINER*) aImage )->Copy( (ZONE_CONTAINER*) aItem );
            ( (ZONE_CONTAINER*) aItem )->Copy( tmp );
            delete tmp;
        }
        break;
202

203
    case PCB_LINE_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
204
#if 0
charras's avatar
charras committed
205 206 207 208
        EXCHG( ( (DRAWSEGMENT*) aItem )->m_Start, ( (DRAWSEGMENT*) aImage )->m_Start );
        EXCHG( ( (DRAWSEGMENT*) aItem )->m_End, ( (DRAWSEGMENT*) aImage )->m_End );
        EXCHG( ( (DRAWSEGMENT*) aItem )->m_Width, ( (DRAWSEGMENT*) aImage )->m_Width );
        EXCHG( ( (DRAWSEGMENT*) aItem )->m_Shape, ( (DRAWSEGMENT*) aImage )->m_Shape );
Dick Hollenbeck's avatar
Dick Hollenbeck committed
209 210 211 212 213 214 215
#else
        {
            DRAWSEGMENT tmp = *(DRAWSEGMENT*) aImage;
            *aImage = *aItem;
            *aItem  = tmp;
        }
#endif
216 217
        break;

218 219
    case PCB_TRACE_T:
    case PCB_VIA_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
        {
            TRACK* track = (TRACK*) aItem;
            TRACK* image = (TRACK*) aImage;
            EXCHG( track->m_Start, image->m_Start );
            EXCHG( track->m_End, image->m_End );
            EXCHG( track->m_Width, image->m_Width );
            EXCHG( track->m_Shape, image->m_Shape );
            int atmp = track->GetDrillValue();

            if( track->IsDrillDefault() )
                atmp = -1;

            int itmp = image->GetDrillValue();

            if( image->IsDrillDefault() )
                itmp = -1;

            EXCHG(itmp, atmp );

            if( atmp > 0 )
                track->SetDrill( atmp );
            else
                track->SetDrillDefault();

            if( itmp > 0 )
                image->SetDrill( itmp );
            else
                image->SetDrillDefault();
        }
249
        break;
250

251
    case PCB_TEXT_T:
252 253 254
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Mirror, ( (TEXTE_PCB*) aImage )->m_Mirror );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Size, ( (TEXTE_PCB*) aImage )->m_Size );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Pos, ( (TEXTE_PCB*) aImage )->m_Pos );
255
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Thickness, ( (TEXTE_PCB*) aImage )->m_Thickness );
256 257 258 259 260 261 262
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Orient, ( (TEXTE_PCB*) aImage )->m_Orient );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Text, ( (TEXTE_PCB*) aImage )->m_Text );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Italic, ( (TEXTE_PCB*) aImage )->m_Italic );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_Bold, ( (TEXTE_PCB*) aImage )->m_Bold );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_HJustify, ( (TEXTE_PCB*) aImage )->m_HJustify );
        EXCHG( ( (TEXTE_PCB*) aItem )->m_VJustify, ( (TEXTE_PCB*) aImage )->m_VJustify );
        break;
263

264
    case PCB_TARGET_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
265
        ( (PCB_TARGET*) aItem )->Exchg( (PCB_TARGET*) aImage );
266
        break;
267

268
    case PCB_DIMENSION_T:
Dick Hollenbeck's avatar
Dick Hollenbeck committed
269 270 271 272 273 274 275 276 277 278 279 280 281
        {
            wxString txt = ( (DIMENSION*) aItem )->GetText();
            ( (DIMENSION*) aItem )->SetText( ( (DIMENSION*) aImage )->GetText() );
            ( (DIMENSION*) aImage )->SetText( txt );
            EXCHG( ( (DIMENSION*) aItem )->m_Width, ( (DIMENSION*) aImage )->m_Width );
            EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Size, ( (DIMENSION*) aImage )->m_Text.m_Size );
            EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Pos, ( (DIMENSION*) aImage )->m_Text.m_Pos );
            EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Thickness,
                   ( (DIMENSION*) aImage )->m_Text.m_Thickness );
            EXCHG( ( (DIMENSION*) aItem )->m_Text.m_Mirror,
                   ( (DIMENSION*) aImage )->m_Text.m_Mirror );
        }
        break;
282

283
    case PCB_ZONE_T:
284 285 286 287 288 289 290
    default:
        wxMessageBox( wxT( "SwapData() error: unexpected type" ) );
        break;
    }
}


291
/*
292
 * Function SaveCopyInUndoList
293
 * Create a copy of the current board item, and put it in the undo list.
294
 *
295
 *  aCommandType =
296 297 298
 *      UR_CHANGED
 *      UR_NEW
 *      UR_DELETED
299 300 301
 *      UR_MOVED
 *      UR_FLIPPED
 *      UR_ROTATED
302
 */
303
void PCB_EDIT_FRAME::SaveCopyInUndoList( BOARD_ITEM*    aItem,
304
                                         UNDO_REDO_T    aCommandType,
305
                                         const wxPoint& aTransformPoint )
306
{
307 308 309
    if( aItem == NULL )     // Nothing to save
        return;

310 311 312 313
    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;

314
    ITEM_PICKER itemWrapper( aItem, aCommandType );
315 316 317

    switch( aCommandType )
    {
318 319 320 321
    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 );
322 323 324
        break;

    case UR_NEW:
325 326 327
    case UR_MOVED:
    case UR_FLIPPED:
    case UR_ROTATED:
charras's avatar
charras committed
328
    case UR_ROTATED_CLOCKWISE:
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
    case UR_DELETED:
        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
351
    {
352
        delete commandToUndo;
353
    }
354 355 356
}


357 358
/**
 * Function SaveCopyInUndoList
359 360
 * @param aItemsList = a PICKED_ITEMS_LIST of items to save
 * @param aTypeCommand = type of comand ( UR_CHANGED, UR_NEW, UR_DELETED ...
361
 * @param aTransformPoint - Transform items around this point.
362
 */
363
void PCB_EDIT_FRAME::SaveCopyInUndoList( PICKED_ITEMS_LIST& aItemsList,
364
                                         UNDO_REDO_T        aTypeCommand,
365
                                         const wxPoint&     aTransformPoint )
366 367 368 369
{
    PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();

    commandToUndo->m_TransformPoint = aTransformPoint;
charras's avatar
charras committed
370

charras's avatar
charras committed
371 372
    // Copy picker list:
    commandToUndo->CopyList( aItemsList );
373

charras's avatar
charras committed
374 375
    // Verify list, and creates data if needed
    for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
376
    {
377 378
        BOARD_ITEM* item    = (BOARD_ITEM*) commandToUndo->GetPickedItem( ii );
        UNDO_REDO_T command = commandToUndo->GetPickedItemStatus( ii );
379

380
        if( command == UR_UNSPECIFIED )
charras's avatar
charras committed
381
        {
382
            command = aTypeCommand;
charras's avatar
charras committed
383
            commandToUndo->SetPickedItemStatus( command, ii );
charras's avatar
charras committed
384
        }
385

386
        wxASSERT( item );
387

388 389
        switch( command )
        {
charras's avatar
charras committed
390
        case UR_CHANGED:
charras's avatar
charras committed
391

charras's avatar
charras committed
392 393 394 395
            /* 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
             */
charras's avatar
charras committed
396
            if( commandToUndo->GetPickedItemLink( ii ) == NULL )
397
                commandToUndo->SetPickedItemLink( item->Clone(), ii );
398 399 400
            break;

        case UR_MOVED:
401
        case UR_ROTATED:
charras's avatar
charras committed
402
        case UR_ROTATED_CLOCKWISE:
403
        case UR_FLIPPED:
404 405 406 407 408 409 410 411 412 413
        case UR_NEW:
        case UR_DELETED:
            break;

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

415
        break;
416

417 418 419 420 421 422 423 424
        }
    }

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

charras's avatar
charras committed
425
        /* Clear redo list, because after a new command one cannot redo a command */
426 427
        GetScreen()->ClearUndoORRedoList( GetScreen()->m_RedoList );
    }
charras's avatar
charras committed
428
    else    // Should not occur
429
    {
430
        delete commandToUndo;
431
    }
432 433 434
}


435
/**
436
 * Function PutDataInPreviousState
437 438 439 440
 * 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
441 442
 * @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)
443
 */
444 445
void PCB_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool aRedoCommand,
                                             bool aRebuildRatsnet )
446 447
{
    BOARD_ITEM* item;
448
    bool        not_found = false;
449
    bool        reBuild_ratsnest = false;
450

charras's avatar
charras committed
451 452
    // 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
453

454
    bool build_item_list = true;    // if true the list of esiting items must be rebuilt
charras's avatar
charras committed
455
    for( int ii = aList->GetCount()-1; ii >= 0 ; ii--  )
456
    {
457
        item = (BOARD_ITEM*) aList->GetPickedItem( ii );
458
        wxASSERT( item );
459 460 461 462 463 464

        /* 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
465
         * Obviouly, this test is not made for deleted items
466
         */
467
        UNDO_REDO_T status = aList->GetPickedItemStatus( ii );
468
        if( status != UR_DELETED )
469
        {
470 471 472 473 474
            if( build_item_list )
                // Build list of existing items, for integrity test
                TestForExistingItem( GetBoard(), NULL );
            build_item_list = false;

475
            if( !TestForExistingItem( GetBoard(), item ) )
476 477
            {
                // Remove this non existant item
charras's avatar
charras committed
478
                aList->RemovePicker( ii );
charras's avatar
charras committed
479
                ii++;       // the current item was removed, ii points now the next item
480
                            // decrement it because it will be incremented later
481 482 483 484
                not_found = true;
                continue;
            }
        }
485

486
        item->ClearFlags();
487

charras's avatar
charras committed
488
        // see if we must rebuild ratsnets and pointers lists
489 490
        switch( item->Type() )
        {
491 492 493 494
        case PCB_MODULE_T:
        case PCB_ZONE_AREA_T:
        case PCB_TRACE_T:
        case PCB_VIA_T:
495 496 497 498 499
            reBuild_ratsnest = true;
            break;

        default:
            break;
500 501
        }

502
        switch( aList->GetPickedItemStatus( ii ) )
503 504
        {
        case UR_CHANGED:    /* Exchange old and new data for each item */
505
        {
506 507
            BOARD_ITEM* image = (BOARD_ITEM*) aList->GetPickedItemLink( ii );
            SwapData( item, image );
508
        }
509
        break;
510 511

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

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

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

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

charras's avatar
charras committed
530 531 532 533
        case UR_ROTATED_CLOCKWISE:
            item->Rotate( aList->m_TransformPoint, aRedoCommand ? -900 : 900 );
            break;

534 535
        case UR_FLIPPED:
            item->Flip( aList->m_TransformPoint );
536 537 538 539 540
            break;

        default:
        {
            wxString msg;
541 542
            msg.Printf( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
                        aList->GetPickedItemStatus( ii ) );
543 544 545 546 547 548
            wxMessageBox( msg );
        }
        break;
        }
    }

549
    if( not_found )
charras's avatar
charras committed
550
        wxMessageBox( wxT( "Incomplete undo/redo operation: some items not found" ) );
551

charras's avatar
charras committed
552
    // Rebuild pointers and rastnest that can be changed.
553
    if( reBuild_ratsnest && aRebuildRatsnet )
554
        Compile_Ratsnest( NULL, true );
555 556 557
}


558 559
/**
 * Function GetBoardFromUndoList
560
 *  Undo the last edition:
charras's avatar
charras committed
561 562
 *  - Save the current board state in Redo list
 *  - Get an old version of the board state from Undo list
563
 *  @return none
564
 */
565
void PCB_EDIT_FRAME::GetBoardFromUndoList( wxCommandEvent& event )
566 567 568 569
{
    if( GetScreen()->GetUndoCommandCount() <= 0 )
        return;

charras's avatar
charras committed
570
    /* Get the old list */
571 572
    PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromUndoList();
    /* Undo the command */
573
    PutDataInPreviousState( List, false );
574

charras's avatar
charras committed
575 576
    /* Put the old list in RedoList */
    List->ReversePickersListOrder();
charras's avatar
charras committed
577 578
    GetScreen()->PushCommandToRedoList( List );

579
    OnModify();
580
    m_canvas->Refresh();
581 582 583
}


584 585
/**
 * Function GetBoardFromRedoList
586 587 588 589
 *  Redo the last edition:
 *  - Save the current board in Undo list
 *  - Get an old version of the board from Redo list
 *  @return none
590
 */
591
void PCB_EDIT_FRAME::GetBoardFromRedoList( wxCommandEvent& event )
592 593 594 595 596
{
    if( GetScreen()->GetRedoCommandCount() == 0 )
        return;


charras's avatar
charras committed
597
    /* Get the old list */
598 599 600
    PICKED_ITEMS_LIST* List = GetScreen()->PopCommandFromRedoList();

    /* Redo the command: */
601
    PutDataInPreviousState( List, true );
602

charras's avatar
charras committed
603 604 605 606
    /* Put the old list in UndoList */
    List->ReversePickersListOrder();
    GetScreen()->PushCommandToUndoList( List );

607
    OnModify();
608
    m_canvas->Refresh();
609 610 611
}


612 613
/**
 * Function ClearUndoORRedoList
614 615 616 617 618 619 620 621 622
 * free the undo or redo list from List element
 *  Wrappers are deleted.
 *  datas pointed by wrappers are deleted if not in use in schematic
 *  i.e. when they are copy of a schematic item or they are no more in use (DELETED)
 * @param aList = the UNDO_REDO_CONTAINER to clear
 * @param aItemCount = the count of items to remove. < 0 for all items
 * items (commands stored in list) are removed from the beginning of the list.
 * So this function can be called to remove old commands
 */
623
void PCB_SCREEN::ClearUndoORRedoList( UNDO_REDO_CONTAINER& aList, int aItemCount )
624 625 626 627 628
{
    if( aItemCount == 0 )
        return;

    unsigned icnt = aList.m_CommandsList.size();
629

630 631
    if( aItemCount > 0 )
        icnt = aItemCount;
charras's avatar
charras committed
632

633 634 635 636
    for( unsigned ii = 0; ii < icnt; ii++ )
    {
        if( aList.m_CommandsList.size() == 0 )
            break;
637

638 639 640
        PICKED_ITEMS_LIST* curr_cmd = aList.m_CommandsList[0];
        aList.m_CommandsList.erase( aList.m_CommandsList.begin() );

charras's avatar
charras committed
641
        curr_cmd->ClearListAndDeleteItems();
642 643 644
        delete curr_cmd;    // Delete command
    }
}