Reconcile zone-auto-fill with undo.

This commit is contained in:
Jeff Young 2022-02-25 13:05:25 +00:00
parent 77f1aad77e
commit bc51c89c90
15 changed files with 112 additions and 85 deletions

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
* Copyright (C) 2007-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2007-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -87,26 +87,9 @@ public:
FOOTPRINT* GetFootprint( const wxString& aFootprintName, REPORTER& aReporter );
/**
* Does nothing in CvPcb but defined because it is a pure virtual in #PCB_BASE_FRAME.
*/
void SaveCopyInUndoList( EDA_ITEM* aItemToCopy, UNDO_REDO aTypeCommand = UNDO_REDO::UNSPECIFIED ) override
{
}
/**
* Create a new entry in undo list of commands.
*
* Add a list of pickers to handle a list of items.
*
* @param aItemsList is the list of items modified by the command to undo
* @param aTypeCommand is command type (see enum UNDO_REDO)
*/
void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO aTypeCommand ) override
{
// currently: do nothing in CvPcb.
}
void SaveCopyInUndoList( EDA_ITEM*, UNDO_REDO ) override {}
void SaveCopyInUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO ) override {}
void AppendCopyToUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO ) override {}
SELECTION& GetCurrentSelection() override;

View File

@ -131,9 +131,7 @@ public:
UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED );
///< Execute the changes.
virtual void Push( const wxString& aMessage = wxT( "A commit" ),
bool aCreateUndoEntry = true, bool aSetDirtyBit = true,
bool aUpdateConnectivity = true, bool aZoneFillOp = false ) = 0;
virtual void Push( const wxString& aMessage = wxT( "A commit" ), int aFlags = 0 ) = 0;
///< Revert the commit by restoring the modified items state.
virtual void Revert() = 0;

View File

@ -333,6 +333,12 @@ public:
virtual void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aTypeCommand ) = 0;
/**
* As SaveCopyInUndoList, but appends the changes to the last undo item on the stack.
*/
virtual void AppendCopyToUndoList( const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aTypeCommand ) = 0;
/**
* Show the dialog box for a layer selection.

View File

@ -140,8 +140,7 @@ void BOARD_COMMIT::dirtyIntersectingZones( BOARD_ITEM* item )
}
void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool aSetDirtyBit,
bool aUpdateConnectivity, bool aZoneFillOp )
void BOARD_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
{
// Objects potentially interested in changes:
PICKED_ITEMS_LIST undoList;
@ -161,7 +160,9 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
if( Empty() )
return;
if( m_isBoardEditor && !aZoneFillOp && frame->GetPcbNewSettings()->m_AutoRefillZones )
if( m_isBoardEditor
&& !( aCommitFlags & ZONE_FILL_OP )
&& frame->GetPcbNewSettings()->m_AutoRefillZones )
{
autofillZones = true;
@ -199,7 +200,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
wxASSERT( ent.m_item->Type() == PCB_FOOTPRINT_T );
wxASSERT( ent.m_copy->Type() == PCB_FOOTPRINT_T );
if( aCreateUndoEntry && frame )
if( !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( nullptr, ent.m_item, UNDO_REDO::CHANGED );
itemWrapper.SetLink( ent.m_copy );
@ -248,7 +249,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
}
else
{
if( aCreateUndoEntry )
if( !( aCommitFlags & SKIP_UNDO ) )
undoList.PushItem( ITEM_PICKER( nullptr, boardItem, UNDO_REDO::NEWITEM ) );
if( !( changeFlags & CHT_DONE ) )
@ -271,7 +272,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
{
PCB_GROUP* parentGroup = boardItem->GetParentGroup();
if( !m_isFootprintEditor && aCreateUndoEntry )
if( !m_isFootprintEditor && !( aCommitFlags & SKIP_UNDO ) )
undoList.PushItem( ITEM_PICKER( nullptr, boardItem, UNDO_REDO::DELETED ) );
if( boardItem->IsSelected() )
@ -403,7 +404,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
case CHT_MODIFY:
{
if( !m_isFootprintEditor && aCreateUndoEntry )
if( !m_isFootprintEditor && !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
wxASSERT( ent.m_copy );
@ -411,7 +412,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
undoList.PushItem( itemWrapper );
}
if( aUpdateConnectivity )
if( !( aCommitFlags & SKIP_CONNECTIVITY ) )
{
std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity();
@ -444,7 +445,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
itemsChanged.push_back( boardItem );
// if no undo entry is needed, the copy would create a memory leak
if( !aCreateUndoEntry )
if( aCommitFlags & SKIP_UNDO )
delete ent.m_copy;
break;
@ -469,7 +470,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
{
size_t num_changes = m_changes.size();
if( aUpdateConnectivity )
if( !( aCommitFlags & SKIP_CONNECTIVITY ) )
{
std::shared_ptr<CONNECTIVITY_DATA> connectivity = board->GetConnectivity();
@ -494,7 +495,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( ent.m_item );
if( aCreateUndoEntry )
if( !( aCommitFlags & SKIP_UNDO ) )
{
ITEM_PICKER itemWrapper( nullptr, boardItem, UNDO_REDO::CHANGED );
wxASSERT( ent.m_copy );
@ -511,8 +512,13 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
}
}
if( m_isBoardEditor && aCreateUndoEntry )
frame->SaveCopyInUndoList( undoList, UNDO_REDO::UNSPECIFIED );
if( m_isBoardEditor && !( aCommitFlags & SKIP_UNDO ) )
{
if( aCommitFlags & APPEND_UNDO )
frame->AppendCopyToUndoList( undoList, UNDO_REDO::UNSPECIFIED );
else
frame->SaveCopyInUndoList( undoList, UNDO_REDO::UNSPECIFIED );
}
m_toolMgr->PostEvent( { TC_MESSAGE, TA_MODEL_CHANGE, AS_GLOBAL } );
@ -524,7 +530,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
if( frame )
{
if( aSetDirtyBit )
if( !( aCommitFlags & SKIP_SET_DIRTY ) )
frame->OnModify();
else
frame->Update3DView( true, frame->Settings().m_Display.m_Live3DRefresh );

View File

@ -35,6 +35,12 @@ class TOOL_MANAGER;
class EDA_DRAW_FRAME;
class TOOL_BASE;
#define SKIP_UNDO 0x0001
#define APPEND_UNDO 0x0002
#define SKIP_SET_DIRTY 0x0004
#define SKIP_CONNECTIVITY 0x0008
#define ZONE_FILL_OP 0x0010
class BOARD_COMMIT : public COMMIT
{
public:
@ -45,14 +51,13 @@ public:
virtual ~BOARD_COMMIT();
virtual void Push( const wxString& aMessage = wxT( "A commit" ),
bool aCreateUndoEntry = true, bool aSetDirtyBit = true,
bool aUpdateConnectivity = true, bool aZoneFillOp = false ) override;
int aCommitFlags = 0 ) override;
virtual void Revert() override;
COMMIT& Stage( EDA_ITEM* aItem, CHANGE_TYPE aChangeType ) override;
COMMIT& Stage( std::vector<EDA_ITEM*>& container, CHANGE_TYPE aChangeType ) override;
COMMIT& Stage(
const PICKED_ITEMS_LIST& aItems, UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED ) override;
COMMIT& Stage( const PICKED_ITEMS_LIST& aItems,
UNDO_REDO aModFlag = UNDO_REDO::UNSPECIFIED ) override;
/**
* Sets a flag that will cause Push() to resolve net conflicts on track/via clusters instead

View File

@ -103,7 +103,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( ZONE* aZone )
commit.Stage( pickedList );
commit.Push( _( "Modify zone properties" ), true, true, false );
commit.Push( _( "Modify zone properties" ), SKIP_CONNECTIVITY );
GetBoard()->GetConnectivity()->Build( GetBoard() );
pickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items

View File

@ -967,7 +967,7 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
filler.SetProgressReporter( &progressReporter );
if( filler.Fill( toFill ) )
commit.Push( _( "Convert Zone(s)" ), true, true, false );
commit.Push( _( "Convert Zone(s)" ), SKIP_CONNECTIVITY );
GetBoard()->BuildConnectivity( &progressReporter );
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2018 Jean-Pierre Charras, jap.charras at wanadoo.fr
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -157,6 +157,7 @@ private:
void SaveCopyInUndoList( EDA_ITEM*, UNDO_REDO ) override {}
void SaveCopyInUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO ) override {}
void AppendCopyToUndoList( const PICKED_ITEMS_LIST&, UNDO_REDO ) override {}
void updateView();

View File

@ -102,6 +102,12 @@ public:
*/
void SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList, UNDO_REDO aCommandType ) override;
/**
* As SaveCopyInUndoList, but appends the changes to the last undo item on the stack.
*/
void AppendCopyToUndoList( const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aCommandType ) override;
/**
* Redo the last edit:
* - Save the current board in Undo list
@ -224,6 +230,9 @@ protected:
void handleActivateEvent( wxActivateEvent& aEvent ) override;
void saveCopyInUndoList( PICKED_ITEMS_LIST* commandToUndo, const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aCommandType );
void unitsChangeRefresh() override;
protected:

View File

@ -877,7 +877,7 @@ void PCB_EDIT_FRAME::ResolveDRCExclusions()
for( PCB_MARKER* marker : GetBoard()->ResolveDRCExclusions() )
commit.Add( marker );
commit.Push( wxEmptyString, false, false );
commit.Push( wxEmptyString, SKIP_UNDO | SKIP_SET_DIRTY );
for( PCB_MARKER* marker : GetBoard()->Markers() )
{

View File

@ -371,7 +371,7 @@ void PCB_EDIT_FRAME::RunActionPlugin( ACTION_PLUGIN* aActionPlugin )
}
// Apply changes, UndoList already handled
commit.Push( _( "Apply action script" ), false );
commit.Push( _( "Apply action script" ), SKIP_UNDO | SKIP_SET_DIRTY );
ActivateGalCanvas();
}

View File

@ -192,7 +192,7 @@ void DRC_TOOL::RunTests( PROGRESS_REPORTER* aProgressReporter, bool aRefillZones
m_drcDialog->SetFootprintTestsRun();
}
commit.Push( _( "DRC" ), false );
commit.Push( _( "DRC" ), SKIP_UNDO );
m_drcRunning = false;

View File

@ -86,7 +86,7 @@ void ZONE_FILLER_TOOL::CheckAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRep
if( filler.Fill( toFill, true, aCaller ) )
{
commit.Push( _( "Fill Zone(s)" ), true, true, false, true );
commit.Push( _( "Fill Zone(s)" ), SKIP_CONNECTIVITY | ZONE_FILL_OP );
getEditFrame<PCB_EDIT_FRAME>()->m_ZoneFillsDirty = false;
}
else
@ -161,7 +161,7 @@ void ZONE_FILLER_TOOL::FillAllZones( wxWindow* aCaller, PROGRESS_REPORTER* aRepo
{
filler.GetProgressReporter()->AdvancePhase();
commit.Push( _( "Fill Zone(s)" ), true, true, false, true );
commit.Push( _( "Fill Zone(s)" ), SKIP_CONNECTIVITY | ZONE_FILL_OP );
frame->m_ZoneFillsDirty = false;
}
else
@ -247,7 +247,7 @@ int ZONE_FILLER_TOOL::ZoneFillDirty( const TOOL_EVENT& aEvent )
}
if( filler.Fill( toFill ) )
commit.Push( _( "Auto-fill Zone(s)" ), false, false, false, true );
commit.Push( _( "Auto-fill Zone(s)" ), APPEND_UNDO | SKIP_CONNECTIVITY | ZONE_FILL_OP );
else
commit.Revert();
@ -270,19 +270,20 @@ int ZONE_FILLER_TOOL::ZoneFillDirty( const TOOL_EVENT& aEvent )
{
WX_INFOBAR* infobar = frame->GetInfoBar();
#ifdef __WXMAC__
// I haven't a clue why this is needed, but if you start another operation before the
// animation is over then you end up accessing deleted view items.
wxShowEffect savedShowEffect = infobar->GetShowEffect();
wxShowEffect savedHideEffect = infobar->GetHideEffect();
int savedEffectDuration = infobar->GetEffectDuration();
infobar->SetShowHideEffects( wxSHOW_EFFECT_NONE, wxSHOW_EFFECT_NONE );
#endif
{
infobar->RemoveAllButtons();
infobar->ShowMessageFor( _( "Zone has no connections." ), 4000, wxICON_WARNING );
}
infobar->SetShowHideEffects( savedShowEffect, savedHideEffect );
infobar->SetEffectDuration( savedEffectDuration );
infobar->RemoveAllButtons();
infobar->ShowMessageFor( _( "Zone has no connections." ), 4000, wxICON_WARNING );
#ifdef __WXMAC__
infobar->SetShowHideEffects( wxSHOW_EFFECT_ROLL_TO_BOTTOM, wxSHOW_EFFECT_ROLL_TO_TOP );
infobar->SetEffectDuration( 300 );
#endif
break;
}
}
@ -330,7 +331,7 @@ int ZONE_FILLER_TOOL::ZoneFill( const TOOL_EVENT& aEvent )
if( filler.Fill( toFill ) )
{
reporter->AdvancePhase();
commit.Push( _( "Fill Zone(s)" ), true, true, false, true );
commit.Push( _( "Fill Zone(s)" ), SKIP_CONNECTIVITY | ZONE_FILL_OP );
}
else
{
@ -367,7 +368,7 @@ int ZONE_FILLER_TOOL::ZoneUnfill( const TOOL_EVENT& aEvent )
zone->UnFill();
}
commit.Push( _( "Unfill Zone" ), true, true, true, true );
commit.Push( _( "Unfill Zone" ), ZONE_FILL_OP );
canvas()->Refresh();
return 0;
@ -385,7 +386,7 @@ int ZONE_FILLER_TOOL::ZoneUnfillAll( const TOOL_EVENT& aEvent )
zone->UnFill();
}
commit.Push( _( "Unfill All Zones" ), true, true, true, true );
commit.Push( _( "Unfill All Zones" ), ZONE_FILL_OP );
canvas()->Refresh();
return 0;

View File

@ -176,18 +176,11 @@ static void SwapItemData( BOARD_ITEM* aItem, BOARD_ITEM* aImage )
}
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aCommandType )
{
PICKED_ITEMS_LIST commandToUndo;
commandToUndo.PushItem( ITEM_PICKER( nullptr, aItem, aCommandType ) );
SaveCopyInUndoList( commandToUndo, aCommandType );
}
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
void PCB_BASE_EDIT_FRAME::saveCopyInUndoList( PICKED_ITEMS_LIST* commandToUndo,
const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aCommandType )
{
PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
int preExisting = commandToUndo->GetCount();
// First, filter unnecessary stuff from the list (i.e. for multiple pads / labels modified),
// take the first occurrence of the footprint (we save copies of footprints when one of its
@ -250,9 +243,9 @@ void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsLis
}
}
for( unsigned ii = 0; ii < commandToUndo->GetCount(); ii++ )
for( unsigned ii = preExisting; ii < commandToUndo->GetCount(); ii++ )
{
EDA_ITEM* item = aItemsList.GetPickedItem( ii );
EDA_ITEM* item = commandToUndo->GetPickedItem( ii );
UNDO_REDO command = commandToUndo->GetPickedItemStatus( ii );
if( command == UNDO_REDO::UNSPECIFIED )
@ -269,15 +262,9 @@ void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsLis
case UNDO_REDO::DRILLORIGIN:
case UNDO_REDO::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 ) == nullptr )
{
EDA_ITEM* cloned = item->Clone();
commandToUndo->SetPickedItemLink( cloned, ii );
}
// If we don't yet have a copy in the link, set one up
if( !commandToUndo->GetPickedItemLink( ii ) )
commandToUndo->SetPickedItemLink( item->Clone(), ii );
break;
@ -312,6 +299,37 @@ void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsLis
}
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( EDA_ITEM* aItem, UNDO_REDO aCommandType )
{
PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
PICKED_ITEMS_LIST itemsList;
itemsList.PushItem( ITEM_PICKER( nullptr, aItem, aCommandType ) );
saveCopyInUndoList( commandToUndo, itemsList, aCommandType );
}
void PCB_BASE_EDIT_FRAME::SaveCopyInUndoList( const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aCommandType )
{
PICKED_ITEMS_LIST* commandToUndo = new PICKED_ITEMS_LIST();
saveCopyInUndoList( commandToUndo, aItemsList, aCommandType );
}
void PCB_BASE_EDIT_FRAME::AppendCopyToUndoList( const PICKED_ITEMS_LIST& aItemsList,
UNDO_REDO aCommandType )
{
PICKED_ITEMS_LIST* commandToUndo = PopCommandFromUndoList();
if( !commandToUndo )
commandToUndo = new PICKED_ITEMS_LIST();
saveCopyInUndoList( commandToUndo, aItemsList, aCommandType );
}
void PCB_BASE_EDIT_FRAME::RestoreCopyFromUndoList( wxCommandEvent& aEvent )
{
if( UndoRedoBlocked() )

View File

@ -118,7 +118,7 @@ void FillZones( BOARD* m_board )
toFill.push_back( zone );
if( filler.Fill( toFill, false, nullptr ) )
commit.Push( _( "Fill Zone(s)" ), false, false );
commit.Push( _( "Fill Zone(s)" ), SKIP_UNDO | SKIP_SET_DIRTY | ZONE_FILL_OP );
}