KiCad PCB EDA Suite
Loading...
Searching...
No Matches
undo_redo.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2012 Jean-Pierre Charras, [email protected]
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 2016 CERN
7 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
8 * @author Maciej Suminski <[email protected]>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include <functional>
25using namespace std::placeholders;
27#include <macros.h>
28#include <pcb_edit_frame.h>
29#include <pcb_track.h>
30#include <pcb_group.h>
31#include <pcb_shape.h>
32#include <pcb_generator.h>
33#include <footprint.h>
34#include <lset.h>
35#include <pad.h>
36#include <origin_viewitem.h>
38#include <tool/tool_manager.h>
39#include <tool/actions.h>
40#include <tools/pcb_actions.h>
42#include <tools/pcb_control.h>
44#include <board_commit.h>
46#include <wx/msgdlg.h>
47#include <pcb_board_outline.h>
48#include <pcb_drill_map.h>
49
50/* Functions to undo and redo edit commands.
51 * commands to undo are stored in CurrentScreen->m_UndoList
52 * commands to redo are stored in CurrentScreen->m_RedoList
53 *
54 * m_UndoList and m_RedoList handle a std::vector of PICKED_ITEMS_LIST
55 * Each PICKED_ITEMS_LIST handle a std::vector of pickers (class ITEM_PICKER),
56 * that store the list of schematic items that are concerned by the command to undo or redo
57 * and is created for each command to undo (handle also a command to redo).
58 * each picker has a pointer pointing to an item to undo or redo (in fact: deleted, added or
59 * modified),
60 * and has a pointer to a copy of this item, when this item has been modified
61 * (the old values of parameters are therefore saved)
62 *
63 * there are 3 cases:
64 * - delete item(s) command
65 * - change item(s) command
66 * - add item(s) command
67 *
68 * Undo command
69 * - delete item(s) command:
70 * => deleted items are moved in undo list
71 *
72 * - change item(s) command
73 * => A copy of item(s) is made (a DrawPickedStruct list of wrappers)
74 * the .m_Link member of each wrapper points the modified item.
75 * the .m_Item member of each wrapper points the old copy of this item.
76 *
77 * - add item(s) command
78 * =>A list of item(s) is made. The .m_Item member of each wrapper points the new item.
79 *
80 * Redo command
81 * - delete item(s) old command:
82 * => deleted items are moved in EEDrawList list, and in
83 *
84 * - change item(s) command
85 * => the copy of item(s) is moved in Undo list
86 *
87 * - add item(s) command
88 * => The list of item(s) is used to create a deleted list in undo list(same as a delete
89 * command)
90 *
91 * Some block operations that change items can be undone without memorize items, just the
92 * coordinates of the transform:
93 * move list of items (undo/redo is made by moving with the opposite move vector)
94 * mirror (Y) and flip list of items (undo/redo is made by mirror or flip items)
95 * so they are handled specifically.
96 *
97 */
98
99
101 const PICKED_ITEMS_LIST& aItemsList,
102 UNDO_REDO aCommandType )
103{
104 int preExisting = (int) commandToUndo->GetCount();
105
106 for( unsigned ii = 0; ii < aItemsList.GetCount(); ii++ )
107 commandToUndo->PushItem( aItemsList.GetItemWrapper(ii) );
108
109 for( unsigned ii = preExisting; ii < commandToUndo->GetCount(); ii++ )
110 {
111 EDA_ITEM* item = commandToUndo->GetPickedItem( ii );
112 UNDO_REDO command = commandToUndo->GetPickedItemStatus( ii );
113
114 if( command == UNDO_REDO::UNSPECIFIED )
115 {
116 command = aCommandType;
117 commandToUndo->SetPickedItemStatus( command, ii );
118 }
119
120 wxASSERT( item );
121
122 switch( command )
123 {
127 // If we don't yet have a copy in the link, set one up
128 if( !commandToUndo->GetPickedItemLink( ii ) )
129 commandToUndo->SetPickedItemLink( BOARD_COMMIT::MakeImage( item ), ii );
130
131 break;
132
136 break;
137
138 default:
139 wxFAIL_MSG( wxString::Format( wxT( "Unrecognized undo command: %X" ), command ) );
140 break;
141 }
142 }
143
144 if( commandToUndo->GetCount() )
145 {
146 /* Save the copy in undo list */
147 PushCommandToUndoList( commandToUndo );
148
149 /* Clear redo list, because after a new command one cannot redo a command */
151 }
152 else
153 {
154 // Should not occur
155 wxASSERT( false );
156 delete commandToUndo;
157 }
158}
159
160
162{
163 PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
164 PICKED_ITEMS_LIST itemsList;
165
166 itemsList.PushItem( ITEM_PICKER( nullptr, aItem, aCommandType ) );
167 saveCopyInUndoList( commandToUndo, itemsList, aCommandType );
168}
169
170
172 UNDO_REDO aCommandType )
173{
174 PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
175 commandToUndo->SetDescription( aItemsList.GetDescription() );
176
177 saveCopyInUndoList( commandToUndo, aItemsList, aCommandType );
178}
179
180
182 UNDO_REDO aCommandType )
183{
184 PICKED_ITEMS_LIST* commandToUndo = PopCommandFromUndoList();
185
186 if( !commandToUndo )
187 {
188 commandToUndo = new PICKED_ITEMS_LIST();
189 commandToUndo->SetDescription( aItemsList.GetDescription() );
190 }
191
192 saveCopyInUndoList( commandToUndo, aItemsList, aCommandType );
193}
194
195
201{
202 for( unsigned ii = 0; ii < aList->GetCount(); ++ii )
203 {
204 switch( aList->GetPickedItem( ii )->Type() )
205 {
206 case PCB_SHAPE_T:
207 case PCB_FOOTPRINT_T:
208 case PCB_TEXT_T:
209 case PCB_TEXTBOX_T:
210 case PCB_FIELD_T:
211 return true;
212
213 default:
214 break;
215 }
216 }
217
218 return false;
219}
220
221
223{
224 for( unsigned ii = 0; ii < aList->GetCount(); ++ii )
225 {
226 if( EDA_ITEM* item = aList->GetPickedItem( ii ) )
227 {
228 if( item->Type() == PCB_DRILL_MAP_T )
229 return true;
230 }
231 }
232
233 return false;
234}
235
236
238{
239 if( UndoRedoBlocked() )
240 return;
241
242 if( GetUndoCommandCount() <= 0 )
243 return;
244
245 // Inform tools that undo command was issued
246 m_toolManager->ProcessEvent( { TC_MESSAGE, TA_UNDO_REDO_PRE, AS_GLOBAL } );
247
248 // Get the old list
250
251 bool shapesChanged = undoListContainsShapesOrFootprints( list );
252 bool drillMapChanged = undoListContainsDrillMap( list );
253
254 // Undo the command
255 PutDataInPreviousState( list, shapesChanged );
256
257 if( drillMapChanged )
258 {
259 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( this ) )
260 editFrame->RefreshDrillSymbols( KIGFX::LAYERS | KIGFX::GEOMETRY | KIGFX::REPAINT );
261 }
262
263 // Put the old list in RedoList
264 list->ReversePickersListOrder();
265 PushCommandToRedoList( list );
266
267 OnModify();
268
271
272 if( shapesChanged )
273 {
274 m_pcb->UpdateBoardOutline();
275 GetCanvas()->GetView()->Update( m_pcb->BoardOutline() );
276 RefreshDrillMapOutlines( *m_pcb, GetCanvas()->GetView() );
277 }
278
279 GetCanvas()->Refresh();
280}
281
282
284{
285 if( UndoRedoBlocked() )
286 return;
287
288 if( GetRedoCommandCount() == 0 )
289 return;
290
291 // Inform tools that redo command was issued
293
294 // Get the old list
296
297 bool shapesChanged = undoListContainsShapesOrFootprints( list );
298 bool drillMapChanged = undoListContainsDrillMap( list );
299
300 // Redo the command
301 PutDataInPreviousState( list, shapesChanged );
302
303 if( drillMapChanged )
304 {
305 if( PCB_EDIT_FRAME* editFrame = dynamic_cast<PCB_EDIT_FRAME*>( this ) )
306 editFrame->RefreshDrillSymbols( KIGFX::LAYERS | KIGFX::GEOMETRY | KIGFX::REPAINT );
307 }
308
309 // Put the old list in UndoList
310 list->ReversePickersListOrder();
311 PushCommandToUndoList( list );
312
313 OnModify();
314
317
318 if( shapesChanged )
319 {
320 m_pcb->UpdateBoardOutline();
321 GetCanvas()->GetView()->Update( m_pcb->BoardOutline() );
322 RefreshDrillMapOutlines( *m_pcb, GetCanvas()->GetView() );
323 }
324
325 GetCanvas()->Refresh();
326}
327
328
330{
331 bool not_found = false;
332 bool reBuild_ratsnest = false;
333 bool deep_reBuild_ratsnest = false; // true later if pointers must be rebuilt
334 bool solder_mask_dirty = false;
335 bool current_show_ratsnest = GetPcbNewSettings()->m_Display.m_ShowGlobalRatsnest;
336 std::vector<BOX2I> dirty_rule_areas;
337
338 KIGFX::PCB_VIEW* view = GetCanvas()->GetView();
339 std::shared_ptr<CONNECTIVITY_DATA> connectivity = GetBoard()->GetConnectivity();
340
341 GetBoard()->IncrementTimeStamp(); // clear caches
342
343 // Enum to track the modification type of items. Used to enable bulk BOARD_LISTENER
344 // callbacks at the end of the undo / redo operation
345 enum ITEM_CHANGE_TYPE
346 {
347 ADDED,
348 DELETED,
349 CHANGED
350 };
351
352 std::unordered_map<EDA_ITEM*, ITEM_CHANGE_TYPE> item_changes;
353
354 auto clear_local_ratsnest_flags =
355 [&]( EDA_ITEM* item )
356 {
357 switch( item->Type() )
358 {
359 case PCB_TRACE_T:
360 case PCB_ARC_T:
361 case PCB_VIA_T:
362 static_cast<PCB_TRACK*>( item )->SetLocalRatsnestVisible( current_show_ratsnest );
363 break;
364
365 case PCB_ZONE_T:
366 static_cast<ZONE*>( item )->SetLocalRatsnestVisible( current_show_ratsnest );
367 break;
368
369 case PCB_FOOTPRINT_T:
370 for( PAD* pad : static_cast<FOOTPRINT*>( item )->Pads() )
371 pad->SetLocalRatsnestVisible( current_show_ratsnest );
372
373 break;
374
375 default:
376 break;
377 }
378 };
379
380 auto update_item_change_state =
381 [&]( EDA_ITEM* item, ITEM_CHANGE_TYPE change_type )
382 {
383 auto item_itr = item_changes.find( item );
384
385 if( item_itr == item_changes.end() )
386 {
387 // First time we've seen this item - tag the current change type
388 item_changes.insert( { item, change_type } );
389 return;
390 }
391
392 // Update the item state based on the current and next change type
393 switch( item_itr->second )
394 {
395 case ITEM_CHANGE_TYPE::ADDED:
396 if( change_type == ITEM_CHANGE_TYPE::DELETED )
397 {
398 // The item was previously added, now deleted - as far as bulk callbacks
399 // are concerned, the item has never existed
400 item_changes.erase( item_itr );
401 }
402 else if( change_type == ITEM_CHANGE_TYPE::ADDED )
403 {
404 // Error condition - added an already added item
405 wxASSERT_MSG( false, wxT( "UndoRedo: should not add already added item" ) );
406 }
407
408 // For all other cases, the item remains as ADDED as seen by the bulk callbacks
409 break;
410
411 case ITEM_CHANGE_TYPE::DELETED:
412 // This is an error condition - item has already been deleted so should not
413 // be operated on further
414 wxASSERT_MSG( false, wxT( "UndoRedo: should not alter already deleted item" ) );
415 break;
416
417 case ITEM_CHANGE_TYPE::CHANGED:
418 if( change_type == ITEM_CHANGE_TYPE::DELETED )
419 {
420 item_itr->second = ITEM_CHANGE_TYPE::DELETED;
421 }
422 else if( change_type == ITEM_CHANGE_TYPE::ADDED )
423 {
424 // This is an error condition - item has already been changed so should not
425 // be added
426 wxASSERT_MSG( false, wxT( "UndoRedo: should not add already changed item" ) );
427 }
428
429 // Otherwise, item remains CHANGED
430 break;
431 }
432 };
433
434 // Undo in the reverse order of list creation: (this can allow stacked changes
435 // like the same item can be changes and deleted in the same complex command
436
437 // Restore changes in reverse order
438 for( int ii = (int) aList->GetCount() - 1; ii >= 0 ; ii-- )
439 {
440 EDA_ITEM* eda_item = aList->GetPickedItem( (unsigned) ii );
441
442 /* Test for existence of item on board.
443 * It could be deleted, and no more on board:
444 * - if a call to SaveCopyInUndoList was forgotten in Pcbnew
445 * - in zones outlines, when a change in one zone merges this zone with an other
446 * This test avoids a Pcbnew crash
447 * Obviously, this test is not made for deleted items
448 */
449 UNDO_REDO status = aList->GetPickedItemStatus( ii );
450
451 if( status != UNDO_REDO::DELETED
452 && status != UNDO_REDO::DRILLORIGIN // origin markers never on board
453 && status != UNDO_REDO::GRIDORIGIN // origin markers never on board
454 && status != UNDO_REDO::PAGESETTINGS ) // nor are page settings proxy items
455 {
456 if( !GetBoard()->ResolveItem( eda_item->m_Uuid, true ) )
457 {
458 // Remove this non existent item
459 aList->RemovePicker( ii );
460 not_found = true;
461
462 if( aList->GetCount() == 0 )
463 break;
464
465 continue;
466 }
467 }
468
469 // see if we must rebuild ratsnets and pointers lists
470 switch( eda_item->Type() )
471 {
472 case PCB_FOOTPRINT_T:
473 deep_reBuild_ratsnest = true; // Pointers on pads can be invalid
475
476 case PCB_ZONE_T:
477 case PCB_TRACE_T:
478 case PCB_ARC_T:
479 case PCB_VIA_T:
480 case PCB_PAD_T:
481 reBuild_ratsnest = true;
482 break;
483
484 case PCB_NETINFO_T:
485 reBuild_ratsnest = true;
486 deep_reBuild_ratsnest = true;
487 break;
488
489 default:
490 break;
491 }
492
493 switch( eda_item->Type() )
494 {
495 case PCB_FOOTPRINT_T:
496 solder_mask_dirty = true;
497 break;
498
499 case PCB_VIA_T:
500 solder_mask_dirty = true;
501 break;
502
503 case PCB_ZONE_T:
504 case PCB_TRACE_T:
505 case PCB_ARC_T:
506 case PCB_PAD_T:
507 case PCB_SHAPE_T:
508 {
509 LSET layers = static_cast<BOARD_ITEM*>( eda_item )->GetLayerSet();
510
511 if( layers.test( F_Mask ) || layers.test( B_Mask ) )
512 solder_mask_dirty = true;
513
514 break;
515 }
516
517 default:
518 break;
519 }
520
521 switch( aList->GetPickedItemStatus( ii ) )
522 {
523 case UNDO_REDO::CHANGED: /* Exchange old and new data for each item */
524 if( eda_item->IsBOARD_ITEM() )
525 {
526 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( eda_item );
527 BOARD_ITEM* image = static_cast<BOARD_ITEM*>( aList->GetPickedItemLink( ii ) );
528 BOARD_ITEM_CONTAINER* parent = GetBoard();
529
530 // The stored pointer can be stale if a swap (e.g. ExchangeFootprint)
531 // replaced the live item earlier. Resolve by UUID to find the current one.
532 if( BOARD_ITEM* resolved = GetBoard()->ResolveItem( item->m_Uuid, true ) )
533 item = resolved;
534
535 if( item->GetParentFootprint() )
536 parent = item->GetParentFootprint();
537
538 view->Remove( item );
539 parent->Remove( item, REMOVE_MODE::BULK );
540
541 if( item->Type() != PCB_MARKER_T )
542 item->SwapItemData( image );
543
544 clear_local_ratsnest_flags( item );
545 item->ClearFlags( UR_TRANSIENT );
546 image->SetFlags( UR_TRANSIENT );
547
548 view->Add( item );
549 view->Hide( item, false );
550 parent->Add( item, ADD_MODE::BULK_INSERT );
551
552 if( item->Type() == PCB_ZONE_T && static_cast<ZONE*>( item )->GetIsRuleArea() )
553 {
554 dirty_rule_areas.push_back( item->GetBoundingBox() );
555 dirty_rule_areas.push_back( image->GetBoundingBox() );
556 }
557
558 update_item_change_state( item, ITEM_CHANGE_TYPE::CHANGED );
559 }
560
561 break;
562
563 case UNDO_REDO::NEWITEM: /* new items are deleted */
564 if( eda_item->IsBOARD_ITEM() )
565 {
566 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( eda_item );
567
569
570 if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
571 parentFP->Remove( boardItem );
572 else
573 GetModel()->Remove( boardItem, REMOVE_MODE::BULK );
574
575 update_item_change_state( eda_item, ITEM_CHANGE_TYPE::DELETED );
576
577 if( eda_item->Type() != PCB_NETINFO_T )
578 view->Remove( eda_item );
579
580 eda_item->SetFlags( UR_TRANSIENT );
581
582 if( eda_item->Type() == PCB_ZONE_T && static_cast<ZONE*>( eda_item )->GetIsRuleArea() )
583 dirty_rule_areas.push_back( eda_item->GetBoundingBox() );
584 }
585
586 break;
587
588 case UNDO_REDO::DELETED: /* deleted items are put in List, as new items */
589 if( eda_item->IsBOARD_ITEM() )
590 {
591 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( eda_item );
592
594
595 clear_local_ratsnest_flags( eda_item );
596 eda_item->ClearFlags( UR_TRANSIENT );
597
598 if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
599 parentFP->Add( boardItem );
600 else
601 GetModel()->Add( boardItem, ADD_MODE::BULK_APPEND );
602
603 update_item_change_state( eda_item, ITEM_CHANGE_TYPE::ADDED );
604
605 if( eda_item->Type() != PCB_NETINFO_T )
606 view->Add( eda_item );
607
608 if( eda_item->Type() == PCB_ZONE_T && static_cast<ZONE*>( eda_item )->GetIsRuleArea() )
609 dirty_rule_areas.push_back( eda_item->GetBoundingBox() );
610 }
611
612 break;
613
616 {
617 // Warning: DRILLORIGIN and GRIDORIGIN undo/redo command create EDA_ITEMs
618 // that cannot be casted to BOARD_ITEMs
619 EDA_ITEM* image = aList->GetPickedItemLink( ii );
620 VECTOR2D origin = image->GetPosition();
621 image->SetPosition( eda_item->GetPosition() );
622
623 if( aList->GetPickedItemStatus( ii ) == UNDO_REDO::DRILLORIGIN )
624 BOARD_EDITOR_CONTROL::DoSetDrillOrigin( view, this, eda_item, origin );
625 else
626 PCB_CONTROL::DoSetGridOrigin( view, this, eda_item, origin );
627
628 break;
629 }
630
632 if( eda_item->Type() == WS_PROXY_UNDO_ITEM_T || eda_item->Type() == WS_PROXY_UNDO_ITEM_PLUS_T )
633 {
634 // swap current settings with stored settings
635 DS_PROXY_UNDO_ITEM alt_item( this );
636 DS_PROXY_UNDO_ITEM* item = static_cast<DS_PROXY_UNDO_ITEM*>( eda_item );
637 item->Restore( this );
638 *item = std::move( alt_item );
639 }
640
641 break;
642
643 default:
644 wxFAIL_MSG( wxString::Format( wxT( "PutDataInPreviousState() error (unknown code %X)" ),
645 aList->GetPickedItemStatus( ii ) ) );
646 break;
647 }
648
649 if( eda_item->Type() == PCB_FOOTPRINT_T )
650 {
651 FOOTPRINT* fp = static_cast<FOOTPRINT*>( eda_item );
653 m_pcb->GetComponentClassManager().RebuildRequiredCaches( fp );
654 }
655 }
656
657 if( not_found )
658 wxMessageBox( _( "Incomplete undo/redo operation: some items not found" ) );
659
660 // We have now swapped all the group parent and group member pointers. But it is a
661 // risky proposition to bet on the pointers being invariant, so validate them all.
662 for( int ii = 0; ii < (int) aList->GetCount(); ++ii )
663 {
664 ITEM_PICKER& wrapper = aList->GetItemWrapper( ii );
665
666 if( wrapper.GetStatus() == UNDO_REDO::DELETED )
667 continue;
668
669 BOARD_ITEM* parentGroup = GetBoard()->ResolveItem( wrapper.GetGroupId(), true );
670 BOARD_ITEM* boardItem = GetBoard()->ResolveItem( wrapper.GetItem()->m_Uuid, true );
671
672 if( boardItem )
673 boardItem->SetParentGroup( dynamic_cast<PCB_GROUP*>( parentGroup ) );
674
675 // Restore the group's member list, which BOARD::Remove() cleared above.
676 if( PCB_GROUP* parentPcbGroup = dynamic_cast<PCB_GROUP*>( parentGroup ) )
677 parentPcbGroup->GetItems().insert( boardItem );
678
679 if( EDA_GROUP* group = dynamic_cast<PCB_GROUP*>( wrapper.GetItem() ) )
680 {
681 // Items list may contain dodgy pointers, so don't use RemoveAll()
682 group->GetItems().clear();
683
684 for( const KIID& member : wrapper.GetGroupMembers() )
685 {
686 if( BOARD_ITEM* memberItem = GetBoard()->ResolveItem( member, true ) )
687 group->AddItem( memberItem );
688 }
689 }
690
691 // And prepare for a redo by updating group info based on current image
692 if( EDA_ITEM* item = wrapper.GetLink() )
693 wrapper.SetLink( item );
694 }
695
696 if( IsType( FRAME_PCB_EDITOR ) )
697 {
698 if( !dirty_rule_areas.empty() && ( GetPcbNewSettings()->m_Display.m_TrackClearance == SHOW_WITH_VIA_ALWAYS
699 || GetPcbNewSettings()->m_Display.m_PadClearance ) )
700 {
701 view->UpdateCollidingItems( dirty_rule_areas, { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T } );
702 }
703
704 if( reBuild_ratsnest || deep_reBuild_ratsnest )
705 {
706 // Connectivity may have changed; rebuild internal caches to remove stale items
709 }
710
711 if( solder_mask_dirty )
713 }
714
716
718 selTool->RebuildSelection();
719
721
722 // Invoke bulk BOARD_LISTENER callbacks
723 std::vector<BOARD_ITEM*> added_items, deleted_items, changed_items;
724
725 for( auto& [item, changeType] : item_changes )
726 {
727 switch( changeType )
728 {
729 case ITEM_CHANGE_TYPE::ADDED:
730 added_items.push_back( static_cast<BOARD_ITEM*>( item ) );
731 break;
732
733 case ITEM_CHANGE_TYPE::DELETED:
734 deleted_items.push_back( static_cast<BOARD_ITEM*>( item ) );
735 break;
736
737 case ITEM_CHANGE_TYPE::CHANGED:
738 changed_items.push_back( static_cast<BOARD_ITEM*>( item ) );
739 break;
740 }
741 }
742
743 if( aRehatchShapes )
745
746 if( added_items.size() > 0 || deleted_items.size() > 0 || changed_items.size() > 0 )
747 GetBoard()->OnItemsCompositeUpdate( added_items, deleted_items, changed_items );
748}
749
750
752{
753 if( aItemCount == 0 )
754 return;
755
756 UNDO_REDO_CONTAINER& list = ( whichList == UNDO_LIST ) ? m_undoList : m_redoList;
757
758 if( aItemCount < 0 )
759 {
760 list.ClearCommandList();
761 }
762 else
763 {
764 for( int ii = 0; ii < aItemCount; ii++ )
765 {
766 if( list.m_CommandsList.size() == 0 )
767 break;
768
769 PICKED_ITEMS_LIST* curr_cmd = list.m_CommandsList[0];
770 list.m_CommandsList.erase( list.m_CommandsList.begin() );
771 ClearListAndDeleteItems( curr_cmd );
772 delete curr_cmd; // Delete command
773 }
774 }
775}
776
777
779{
781 []( EDA_ITEM* item )
782 {
783 wxASSERT_MSG( item->HasFlag( UR_TRANSIENT ),
784 "Item on undo/redo list not owned by undo/redo!" );
785
786 delete item;
787 } );
788}
789
790
792{
796 delete undo;
797
798 m_pcb->UpdateBoardOutline();
799 GetCanvas()->GetView()->Update( m_pcb->BoardOutline() );
800 RefreshDrillMapOutlines( *m_pcb, GetCanvas()->GetView() );
801 GetCanvas()->Refresh();
802}
static EDA_ITEM * MakeImage(EDA_ITEM *aItem)
static void DoSetDrillOrigin(KIGFX::VIEW *aView, PCB_BASE_FRAME *aFrame, EDA_ITEM *aItem, const VECTOR2D &aPoint)
Abstract interface for BOARD_ITEMs capable of storing other items inside.
virtual void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL)=0
Removes an item from the container.
virtual void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false)=0
Adds an item to the container.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition board_item.h:84
void SwapItemData(BOARD_ITEM *aImage)
Swap data between aItem and aImage.
FOOTPRINT * GetParentFootprint() const
void CompileRatsnest()
Rebuild the entire board ratsnest.
Definition board.cpp:4039
void SanitizeNetcodes()
Definition board.cpp:3954
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition board.cpp:364
void OnItemsCompositeUpdate(std::vector< BOARD_ITEM * > &aAddedItems, std::vector< BOARD_ITEM * > &aRemovedItems, std::vector< BOARD_ITEM * > &aChangedItems)
Notify the board and its listeners that items on the board have been modified in a composite operatio...
Definition board.cpp:4022
void IncrementTimeStamp()
Definition board.cpp:446
COMPONENT_CLASS_MANAGER & GetComponentClassManager()
Gets the component class manager.
Definition board.h:1668
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
Definition board.cpp:2116
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:751
void InvalidateComponentClasses()
Invalidates any caches component classes and recomputes caches if required.
void Restore(EDA_DRAW_FRAME *aFrame, KIGFX::VIEW *aView=nullptr)
virtual void PushCommandToUndoList(PICKED_ITEMS_LIST *aItem)
Add a command to undo in the undo list.
virtual int GetRedoCommandCount() const
UNDO_REDO_CONTAINER m_undoList
UNDO_REDO_LIST
Specify whether we are interacting with the undo or redo stacks.
virtual PICKED_ITEMS_LIST * PopCommandFromRedoList()
Return the last command to undo and remove it from list, nothing is deleted.
UNDO_REDO_CONTAINER m_redoList
virtual PICKED_ITEMS_LIST * PopCommandFromUndoList()
Return the last command to undo and remove it from list, nothing is deleted.
virtual int GetUndoCommandCount() const
virtual void PushCommandToRedoList(PICKED_ITEMS_LIST *aItem)
Add a command to redo in the redo list.
bool IsType(FRAME_T aType) const
virtual void Refresh(bool aEraseBackground=true, const wxRect *aRect=nullptr) override
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:43
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
virtual VECTOR2I GetPosition() const
Definition eda_item.h:348
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition eda_item.h:158
const KIID m_Uuid
Definition eda_item.h:597
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
void ClearFlags(EDA_ITEM_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition eda_item.h:160
virtual void SetParentGroup(EDA_GROUP *aGroup)
Definition eda_item.h:115
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
static const TOOL_EVENT UndoRedoPreEvent
Definition actions.h:366
static const TOOL_EVENT SelectedItemsModified
Selected items were moved, this can be very high frequency on the canvas, use with care.
Definition actions.h:350
static const TOOL_EVENT UndoRedoPostEvent
Definition actions.h:367
void InvalidateComponentClassCache() const
Forces deferred (on next access) recalculation of the component class for this footprint.
virtual void Update(const VIEW_ITEM *aItem, int aUpdateFlags) const override
For dynamic VIEWs, inform the associated VIEW that the graphical representation of this item has chan...
Definition pcb_view.cpp:87
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1) override
Add a VIEW_ITEM to the view.
Definition pcb_view.cpp:53
void UpdateCollidingItems(const std::vector< BOX2I > &aStaleAreas, std::initializer_list< KICAD_T > aTypes)
Sets the KIGFX::REPAINT on all items matching aTypes which intersect aStaleAreas.
Definition pcb_view.cpp:118
virtual void Remove(VIEW_ITEM *aItem) override
Remove a VIEW_ITEM from the view.
Definition pcb_view.cpp:70
bool IsBOARD_ITEM() const
Definition view_item.h:98
void Hide(VIEW_ITEM *aItem, bool aHide=true, bool aHideOverlay=false)
Temporarily hide the item in the view (e.g.
Definition view.cpp:1797
Definition kiid.h:46
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
Definition pad.h:61
DISPLAY_OPTIONS m_Display
static TOOL_ACTION rehatchShapes
void ClearUndoORRedoList(UNDO_REDO_LIST whichList, int aItemCount=-1) override
Free the undo or redo list from List element.
void RestoreCopyFromUndoList(wxCommandEvent &aEvent)
Undo the last edit:
void saveCopyInUndoList(PICKED_ITEMS_LIST *commandToUndo, const PICKED_ITEMS_LIST &aItemsList, UNDO_REDO aCommandType)
void AppendCopyToUndoList(const PICKED_ITEMS_LIST &aItemsList, UNDO_REDO aCommandType) override
As SaveCopyInUndoList, but appends the changes to the last undo item on the stack.
void SaveCopyInUndoList(EDA_ITEM *aItemToCopy, UNDO_REDO aTypeCommand) override
Create a new entry in undo list of commands.
void ClearListAndDeleteItems(PICKED_ITEMS_LIST *aList)
void RollbackFromUndo()
Perform an undo of the last edit without logging a corresponding redo.
bool UndoRedoBlocked() const
Check if the undo and redo operations are currently blocked.
void RestoreCopyFromRedoList(wxCommandEvent &aEvent)
Redo the last edit:
void PutDataInPreviousState(PICKED_ITEMS_LIST *aList, bool aRehatchShapes=true)
Used in undo or redo command.
PCBNEW_SETTINGS * GetPcbNewSettings() const
void OnModify() override
Must be called after a change in order to set the "modify" flag and update other data structures and ...
EDA_ITEM * ResolveItem(const KIID &aId, bool aAllowNullptrReturn=false) const override
Fetch an item by KIID.
PCB_DRAW_PANEL_GAL * GetCanvas() const override
Return a pointer to GAL-based canvas of given EDA draw frame.
BOARD * GetBoard() const
virtual BOARD_ITEM_CONTAINER * GetModel() const =0
static void DoSetGridOrigin(KIGFX::VIEW *aView, PCB_BASE_FRAME *aFrame, EDA_ITEM *originViewItem, const VECTOR2D &aPoint)
virtual KIGFX::PCB_VIEW * GetView() const override
Return a pointer to the #VIEW instance used in the panel.
The main frame for Pcbnew.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:51
The selection tool: currently supports:
void RebuildSelection()
Rebuild the selection from the EDA_ITEMs' selection flags.
A holder to handle information on schematic or board items.
bool SetPickedItemStatus(UNDO_REDO aStatus, unsigned aIdx)
Set the type of undo/redo operation for a given picked item.
void PushItem(const ITEM_PICKER &aItem)
Push aItem to the top of the list.
void SetDescription(const wxString &aDescription)
UNDO_REDO GetPickedItemStatus(unsigned int aIdx) const
EDA_ITEM * GetPickedItemLink(unsigned int aIdx) const
wxString GetDescription() const
bool RemovePicker(unsigned aIdx)
Remove one entry (one picker) from the list of picked items.
const ITEM_PICKER & GetItemWrapper(unsigned int aIdx) const
unsigned GetCount() const
bool SetPickedItemLink(EDA_ITEM *aLink, unsigned aIdx)
Set the link associated to a given picked item.
void ClearListAndDeleteItems(std::function< void(EDA_ITEM *)> aItemDeleter)
Delete the list of pickers AND the data pointed by #m_PickedItem or #m_PickedItemLink according to th...
EDA_ITEM * GetPickedItem(unsigned int aIdx) const
TOOL_MANAGER * m_toolManager
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
bool PostAction(const std::string &aActionName, T aParam)
Run the specified action after the current action (coroutine) ends.
A holder to handle a list of undo (or redo) commands.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:807
#define _(s)
#define UR_TRANSIENT
indicates the item is owned by the undo/redo stack
@ FRAME_PCB_EDITOR
Definition frame_type.h:38
@ B_Mask
Definition layer_ids.h:94
@ F_Mask
Definition layer_ids.h:93
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
@ REPAINT
Item needs to be redrawn.
Definition view_item.h:54
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:51
@ LAYERS
Layers have changed.
Definition view_item.h:52
void RefreshDrillMapOutlines(const BOARD &aBoard, KIGFX::VIEW *aView)
Repaint every drill map after an Edge.Cuts edit.
Class to handle a set of BOARD_ITEMs.
@ SHOW_WITH_VIA_ALWAYS
@ AS_GLOBAL
Global action (toolbar/main menu event, global shortcut)
Definition tool_action.h:45
@ TA_UNDO_REDO_PRE
This event is sent before undo/redo command is performed.
Definition tool_event.h:102
@ TA_UNDO_REDO_POST
This event is sent after undo/redo command is performed.
Definition tool_event.h:105
@ TC_MESSAGE
Definition tool_event.h:54
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition typeinfo.h:80
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition typeinfo.h:89
@ PCB_DRILL_MAP_T
class PCB_DRILL_MAP, drill symbols drawn at the holes
Definition typeinfo.h:240
@ PCB_TEXTBOX_T
class PCB_TEXTBOX, wrapped text on a layer
Definition typeinfo.h:85
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition typeinfo.h:84
@ PCB_FIELD_T
class PCB_FIELD, text associated with a footprint property
Definition typeinfo.h:82
@ PCB_MARKER_T
class PCB_MARKER, a marker used to show something
Definition typeinfo.h:91
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition typeinfo.h:78
@ WS_PROXY_UNDO_ITEM_T
Definition typeinfo.h:220
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition typeinfo.h:79
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition typeinfo.h:90
@ WS_PROXY_UNDO_ITEM_PLUS_T
Definition typeinfo.h:221
@ PCB_NETINFO_T
class NETINFO_ITEM, a description of a net
Definition typeinfo.h:102
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition typeinfo.h:88
static bool undoListContainsShapesOrFootprints(const PICKED_ITEMS_LIST *aList)
Check whether the undo/redo list contains any items that could affect the board outline or shape hatc...
static bool undoListContainsDrillMap(const PICKED_ITEMS_LIST *aList)
UNDO_REDO
Undo Redo considerations: Basically we have 3 cases New item Deleted item Modified item there is also...
VECTOR2< double > VECTOR2D
Definition vector2d.h:682