cvpcb: Add undo/redo functionality to the associations

This commit is contained in:
Ian McInerney 2019-07-26 20:58:20 +02:00 committed by Wayne Stambaugh
parent 402031244d
commit 06abda254a
8 changed files with 194 additions and 10 deletions

View File

@ -193,6 +193,7 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
m_skipComponentSelect = true; m_skipComponentSelect = true;
error_msg.Empty(); error_msg.Empty();
bool firstAssoc = true;
for( unsigned kk = 0; kk < m_netlist.GetCount(); kk++ ) for( unsigned kk = 0; kk < m_netlist.GetCount(); kk++ )
{ {
COMPONENT* component = m_netlist.GetComponent( kk ); COMPONENT* component = m_netlist.GetComponent( kk );
@ -232,7 +233,9 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
// If the equivalence is unique, no ambiguity: use the association // If the equivalence is unique, no ambiguity: use the association
if( module && equ_is_unique ) if( module && equ_is_unique )
{ {
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ) ); AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ),
firstAssoc );
firstAssoc = false;
found = true; found = true;
break; break;
} }
@ -270,7 +273,8 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
if( found ) if( found )
{ {
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ) ); AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ), firstAssoc );
firstAssoc = false;
break; break;
} }
} }
@ -279,7 +283,8 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
continue; continue;
else if( !fpid_candidate.IsEmpty() ) else if( !fpid_candidate.IsEmpty() )
{ {
AssociateFootprint( CVPCB_ASSOCIATION( kk, fpid_candidate ) ); AssociateFootprint( CVPCB_ASSOCIATION( kk, fpid_candidate ), firstAssoc );
firstAssoc = false;
continue; continue;
} }
@ -291,7 +296,11 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
const FOOTPRINT_INFO* module = m_FootprintsList->GetModuleInfo( component->GetFootprintFilters()[0] ); const FOOTPRINT_INFO* module = m_FootprintsList->GetModuleInfo( component->GetFootprintFilters()[0] );
if( module ) if( module )
AssociateFootprint( CVPCB_ASSOCIATION( kk, component->GetFootprintFilters()[0] ) ); {
AssociateFootprint( CVPCB_ASSOCIATION( kk, component->GetFootprintFilters()[0] ),
firstAssoc );
firstAssoc = false;
}
} }
} }

View File

@ -60,7 +60,7 @@ public:
* *
* @return the reversed association * @return the reversed association
*/ */
CVPCB_ASSOCIATION Reverse() CVPCB_ASSOCIATION Reverse() const
{ {
return CVPCB_ASSOCIATION( m_componentIndex, m_oldFootprint, m_newFootprint ); return CVPCB_ASSOCIATION( m_componentIndex, m_oldFootprint, m_newFootprint );
} }

View File

@ -404,7 +404,47 @@ void CVPCB_MAINFRAME::OnQuit( wxCommandEvent& event )
} }
void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation ) void CVPCB_MAINFRAME::UndoAssociation()
{
if( m_undoList.size() == 0 )
return;
CVPCB_UNDO_REDO_ENTRIES redoEntries;
CVPCB_UNDO_REDO_ENTRIES curEntry = m_undoList.back();
m_undoList.pop_back();
// Iterate over the entries to undo
for( auto assoc : curEntry )
{
AssociateFootprint( assoc, true, false );
redoEntries.emplace_back( assoc.Reverse() );
}
// Add the redo entries to the redo stack
m_redoList.emplace_back( redoEntries );
}
void CVPCB_MAINFRAME::RedoAssociation()
{
if( m_redoList.size() == 0 )
return;
CVPCB_UNDO_REDO_ENTRIES curEntry = m_redoList.back();
m_redoList.pop_back();
// Iterate over the entries to undo
bool firstAssoc = true;
for( auto assoc : curEntry )
{
AssociateFootprint( assoc, firstAssoc );
firstAssoc = false;
}
}
void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation,
bool aNewEntry, bool aAddUndoItem )
{ {
// Ensure there is data to work with // Ensure there is data to work with
COMPONENT* component; COMPONENT* component;
@ -417,7 +457,8 @@ void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation
if( component == NULL ) if( component == NULL )
return; return;
LIB_ID fpid = aAssociation.GetNewFootprint(); LIB_ID fpid = aAssociation.GetNewFootprint();
LIB_ID oldFpid = component->GetFPID();
// Test for validity of the requested footprint // Test for validity of the requested footprint
if( !fpid.empty() && !fpid.IsValid() ) if( !fpid.empty() && !fpid.IsValid() )
@ -442,6 +483,26 @@ void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation
// Update the statusbar and refresh the list // Update the statusbar and refresh the list
DisplayStatus(); DisplayStatus();
m_compListBox->Refresh(); m_compListBox->Refresh();
if( !aAddUndoItem )
return;
// Update the undo list
if ( aNewEntry )
{
// Create a new entry for this association
CVPCB_UNDO_REDO_ENTRIES newEntry;
newEntry.emplace_back( CVPCB_ASSOCIATION( aAssociation.GetComponentIndex(), oldFpid,
aAssociation.GetNewFootprint() ) );
m_undoList.emplace_back( newEntry );
// Clear the redo list
m_redoList.clear();
}
else
m_undoList.back().emplace_back( CVPCB_ASSOCIATION( aAssociation.GetComponentIndex(),
oldFpid, aAssociation.GetNewFootprint() ) );
} }
@ -454,9 +515,11 @@ void CVPCB_MAINFRAME::DeleteAll()
// Remove all selections to avoid issues when setting the fpids // Remove all selections to avoid issues when setting the fpids
m_compListBox->DeselectAll(); m_compListBox->DeselectAll();
bool firstAssoc = true;
for( unsigned i = 0; i < m_netlist.GetCount(); i++ ) for( unsigned i = 0; i < m_netlist.GetCount(); i++ )
{ {
AssociateFootprint( CVPCB_ASSOCIATION( i, LIB_ID() ) ); AssociateFootprint( CVPCB_ASSOCIATION( i, LIB_ID() ), firstAssoc );
firstAssoc = false;
} }
// Remove all selections after setting the fpids // Remove all selections after setting the fpids

View File

@ -46,6 +46,12 @@ class FP_LIB_TABLE;
namespace CV { struct IFACE; } namespace CV { struct IFACE; }
// The undo/redo list is composed of vectors of associations
typedef std::vector< CVPCB_ASSOCIATION > CVPCB_UNDO_REDO_ENTRIES;
// The undo list is a vector of undo entries
typedef std::vector< CVPCB_UNDO_REDO_ENTRIES > CVPCB_UNDO_REDO_LIST;
/** /**
* The CvPcb application main window. * The CvPcb application main window.
*/ */
@ -170,12 +176,30 @@ public:
*/ */
void OnEnterFilteringText( wxCommandEvent& event ); void OnEnterFilteringText( wxCommandEvent& event );
/**
* Undo the most recent associations that were performed.
*/
void UndoAssociation();
/**
* Redo the most recently undone association
*/
void RedoAssociation();
/** /**
* Associate a footprint with a specific component in the list. * Associate a footprint with a specific component in the list.
* *
* Associations can be chained into a single undo/redo step by setting aNewEntry to false
* for every association other than the first one. This will create a new list entry for
* the first association, and add the subsequent associations to that list.
*
* @param aAssociation is the association to perform * @param aAssociation is the association to perform
* @param aNewEntry specifies if this association should be a new entry in the undo list
* @param aAddUndoItem specifies if an undo item should be created for this association
*/ */
void AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation ); void AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation, bool aNewEntry = true,
bool aAddUndoItem = true );
void BuildCmpListBox(); void BuildCmpListBox();
void BuildFOOTPRINTS_LISTBOX(); void BuildFOOTPRINTS_LISTBOX();
@ -318,6 +342,10 @@ private:
ACTION_MENU* m_footprintContextMenu; ACTION_MENU* m_footprintContextMenu;
ACTION_MENU* m_componentContextMenu; ACTION_MENU* m_componentContextMenu;
// Undo/Redo item lists
CVPCB_UNDO_REDO_LIST m_undoList;
CVPCB_UNDO_REDO_LIST m_redoList;
DECLARE_EVENT_TABLE() DECLARE_EVENT_TABLE()
}; };

View File

@ -51,6 +51,24 @@ void CVPCB_MAINFRAME::ReCreateMenuBar()
fileMenu->Resolve(); fileMenu->Resolve();
//-- Preferences menu -----------------------------------------------
//
CONDITIONAL_MENU* editMenu = new CONDITIONAL_MENU( false, tool );
auto enableUndoCondition = [ this ] ( const SELECTION& sel )
{
return m_undoList.size() > 0;
};
auto enableRedoCondition = [ this ] ( const SELECTION& sel )
{
return m_redoList.size() > 0;
};
editMenu->AddItem( ACTIONS::undo, enableUndoCondition );
editMenu->AddItem( ACTIONS::redo, enableRedoCondition );
editMenu->Resolve();
//-- Preferences menu ----------------------------------------------- //-- Preferences menu -----------------------------------------------
// //
CONDITIONAL_MENU* prefsMenu = new CONDITIONAL_MENU( false, tool ); CONDITIONAL_MENU* prefsMenu = new CONDITIONAL_MENU( false, tool );
@ -72,6 +90,7 @@ void CVPCB_MAINFRAME::ReCreateMenuBar()
//-- Menubar ------------------------------------------------------------- //-- Menubar -------------------------------------------------------------
// //
menuBar->Append( fileMenu, _( "&File" ) ); menuBar->Append( fileMenu, _( "&File" ) );
menuBar->Append( editMenu, _( "&Edit" ) );
menuBar->Append( prefsMenu, _( "&Preferences" ) ); menuBar->Append( prefsMenu, _( "&Preferences" ) );
AddStandardHelpMenu( menuBar ); AddStandardHelpMenu( menuBar );

View File

@ -54,6 +54,8 @@ void CVPCB_MAINFRAME::ReCreateHToolbar()
m_mainToolBar->Add( CVPCB_ACTIONS::gotoNextNA ); m_mainToolBar->Add( CVPCB_ACTIONS::gotoNextNA );
KiScaledSeparator( m_mainToolBar, this ); KiScaledSeparator( m_mainToolBar, this );
m_mainToolBar->Add( ACTIONS::undo );
m_mainToolBar->Add( ACTIONS::redo );
m_mainToolBar->Add( CVPCB_ACTIONS::autoAssociate ); m_mainToolBar->Add( CVPCB_ACTIONS::autoAssociate );
m_mainToolBar->Add( CVPCB_ACTIONS::deleteAll ); m_mainToolBar->Add( CVPCB_ACTIONS::deleteAll );
@ -86,6 +88,9 @@ void CVPCB_MAINFRAME::SyncToolbars()
{ {
#define filterActive( filt ) ( m_filteringOptions & filt ) #define filterActive( filt ) ( m_filteringOptions & filt )
m_mainToolBar->Toggle( ACTIONS::undo, m_undoList.size() > 0 );
m_mainToolBar->Toggle( ACTIONS::redo, m_redoList.size() > 0 );
m_mainToolBar->Toggle( CVPCB_ACTIONS::filterFPbyKeywords, m_mainToolBar->Toggle( CVPCB_ACTIONS::filterFPbyKeywords,
filterActive( FOOTPRINTS_LISTBOX::FILTERING_BY_COMPONENT_KEYWORD ) ); filterActive( FOOTPRINTS_LISTBOX::FILTERING_BY_COMPONENT_KEYWORD ) );
m_mainToolBar->Toggle( CVPCB_ACTIONS::filterFPbyLibrary, m_mainToolBar->Toggle( CVPCB_ACTIONS::filterFPbyLibrary,

View File

@ -96,6 +96,22 @@ int CVPCB_CONTROL::ToggleFootprintFilter( const TOOL_EVENT& aEvent )
} }
int CVPCB_CONTROL::Undo( const TOOL_EVENT& aEvent )
{
m_frame->UndoAssociation();
return 0;
}
int CVPCB_CONTROL::Redo( const TOOL_EVENT& aEvent )
{
m_frame->RedoAssociation();
return 0;
}
int CVPCB_CONTROL::Associate( const TOOL_EVENT& aEvent ) int CVPCB_CONTROL::Associate( const TOOL_EVENT& aEvent )
{ {
// Get the currently selected footprint // Get the currently selected footprint
@ -118,10 +134,12 @@ int CVPCB_CONTROL::Associate( const TOOL_EVENT& aEvent )
// Get all the components that are selected and associate them with the current footprint // Get all the components that are selected and associate them with the current footprint
std::vector<unsigned int> sel = m_frame->GetSelectedComponentIndices(); std::vector<unsigned int> sel = m_frame->GetSelectedComponentIndices();
bool firstAssoc = true;
for( auto i : sel ) for( auto i : sel )
{ {
CVPCB_ASSOCIATION newfp( i, fpid ); CVPCB_ASSOCIATION newfp( i, fpid );
m_frame->AssociateFootprint( newfp ); m_frame->AssociateFootprint( newfp, firstAssoc );
firstAssoc = false;
} }
return 0; return 0;
@ -174,8 +192,27 @@ int CVPCB_CONTROL::ToPreviousNA( const TOOL_EVENT& aEvent )
} }
int CVPCB_CONTROL::UpdateMenu( const TOOL_EVENT& aEvent )
{
ACTION_MENU* actionMenu = aEvent.Parameter<ACTION_MENU*>();
CONDITIONAL_MENU* conditionalMenu = dynamic_cast<CONDITIONAL_MENU*>( actionMenu );
SELECTION dummySel;
if( conditionalMenu )
conditionalMenu->Evaluate( dummySel );
if( actionMenu )
actionMenu->UpdateAll();
return 0;
}
void CVPCB_CONTROL::setTransitions() void CVPCB_CONTROL::setTransitions()
{ {
// Update the menu
Go( &CVPCB_CONTROL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() );
// Run the footprint viewer // Run the footprint viewer
Go( &CVPCB_CONTROL::ShowFootprintViewer, CVPCB_ACTIONS::showFootprintViewer.MakeEvent() ); Go( &CVPCB_CONTROL::ShowFootprintViewer, CVPCB_ACTIONS::showFootprintViewer.MakeEvent() );
@ -189,6 +226,8 @@ void CVPCB_CONTROL::setTransitions()
Go( &CVPCB_CONTROL::ToPreviousNA, CVPCB_ACTIONS::gotoPreviousNA.MakeEvent() ); Go( &CVPCB_CONTROL::ToPreviousNA, CVPCB_ACTIONS::gotoPreviousNA.MakeEvent() );
// Footprint association actions // Footprint association actions
Go( &CVPCB_CONTROL::Undo, ACTIONS::undo.MakeEvent() );
Go( &CVPCB_CONTROL::Redo, ACTIONS::redo.MakeEvent() );
Go( &CVPCB_CONTROL::Associate, CVPCB_ACTIONS::associate.MakeEvent() ); Go( &CVPCB_CONTROL::Associate, CVPCB_ACTIONS::associate.MakeEvent() );
Go( &CVPCB_CONTROL::AutoAssociate, CVPCB_ACTIONS::autoAssociate.MakeEvent() ); Go( &CVPCB_CONTROL::AutoAssociate, CVPCB_ACTIONS::autoAssociate.MakeEvent() );

View File

@ -41,6 +41,20 @@ public:
/// @copydoc TOOL_INTERACTIVE::Reset() /// @copydoc TOOL_INTERACTIVE::Reset()
void Reset( RESET_REASON aReason ) override; void Reset( RESET_REASON aReason ) override;
/**
* Undo the footprint associations most recently done.
*
* @param aEvent is the event generated by the tool framework
*/
int Undo( const TOOL_EVENT& aEvent );
/**
* Redo the footprint associations most recently done.
*
* @param aEvent is the event generated by the tool framework
*/
int Redo( const TOOL_EVENT& aEvent );
/** /**
* Associate the selected footprint with the currently selected components. * Associate the selected footprint with the currently selected components.
* *
@ -107,6 +121,13 @@ public:
*/ */
int ToggleFootprintFilter( const TOOL_EVENT& aEvent ); int ToggleFootprintFilter( const TOOL_EVENT& aEvent );
/**
* Update the menu to reflect the current tool states.
*
* @param aEvent is the event generated by the tool framework
*/
int UpdateMenu( const TOOL_EVENT& aEvent );
/* /*
* Sets up handlers for various events. * Sets up handlers for various events.
*/ */