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;
error_msg.Empty();
bool firstAssoc = true;
for( unsigned kk = 0; kk < m_netlist.GetCount(); 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( module && equ_is_unique )
{
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ) );
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ),
firstAssoc );
firstAssoc = false;
found = true;
break;
}
@ -270,7 +273,8 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
if( found )
{
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ) );
AssociateFootprint( CVPCB_ASSOCIATION( kk, equivItem.m_FootprintFPID ), firstAssoc );
firstAssoc = false;
break;
}
}
@ -279,7 +283,8 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
continue;
else if( !fpid_candidate.IsEmpty() )
{
AssociateFootprint( CVPCB_ASSOCIATION( kk, fpid_candidate ) );
AssociateFootprint( CVPCB_ASSOCIATION( kk, fpid_candidate ), firstAssoc );
firstAssoc = false;
continue;
}
@ -291,7 +296,11 @@ void CVPCB_MAINFRAME::AutomaticFootprintMatching()
const FOOTPRINT_INFO* module = m_FootprintsList->GetModuleInfo( component->GetFootprintFilters()[0] );
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
*/
CVPCB_ASSOCIATION Reverse()
CVPCB_ASSOCIATION Reverse() const
{
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
COMPONENT* component;
@ -417,7 +457,8 @@ void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation
if( component == NULL )
return;
LIB_ID fpid = aAssociation.GetNewFootprint();
LIB_ID fpid = aAssociation.GetNewFootprint();
LIB_ID oldFpid = component->GetFPID();
// Test for validity of the requested footprint
if( !fpid.empty() && !fpid.IsValid() )
@ -442,6 +483,26 @@ void CVPCB_MAINFRAME::AssociateFootprint( const CVPCB_ASSOCIATION& aAssociation
// Update the statusbar and refresh the list
DisplayStatus();
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
m_compListBox->DeselectAll();
bool firstAssoc = true;
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

View File

@ -46,6 +46,12 @@ class FP_LIB_TABLE;
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.
*/
@ -170,12 +176,30 @@ public:
*/
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.
*
* 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 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 BuildFOOTPRINTS_LISTBOX();
@ -318,6 +342,10 @@ private:
ACTION_MENU* m_footprintContextMenu;
ACTION_MENU* m_componentContextMenu;
// Undo/Redo item lists
CVPCB_UNDO_REDO_LIST m_undoList;
CVPCB_UNDO_REDO_LIST m_redoList;
DECLARE_EVENT_TABLE()
};

View File

@ -51,6 +51,24 @@ void CVPCB_MAINFRAME::ReCreateMenuBar()
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 -----------------------------------------------
//
CONDITIONAL_MENU* prefsMenu = new CONDITIONAL_MENU( false, tool );
@ -72,6 +90,7 @@ void CVPCB_MAINFRAME::ReCreateMenuBar()
//-- Menubar -------------------------------------------------------------
//
menuBar->Append( fileMenu, _( "&File" ) );
menuBar->Append( editMenu, _( "&Edit" ) );
menuBar->Append( prefsMenu, _( "&Preferences" ) );
AddStandardHelpMenu( menuBar );

View File

@ -54,6 +54,8 @@ void CVPCB_MAINFRAME::ReCreateHToolbar()
m_mainToolBar->Add( CVPCB_ACTIONS::gotoNextNA );
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::deleteAll );
@ -86,6 +88,9 @@ void CVPCB_MAINFRAME::SyncToolbars()
{
#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,
filterActive( FOOTPRINTS_LISTBOX::FILTERING_BY_COMPONENT_KEYWORD ) );
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 )
{
// 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
std::vector<unsigned int> sel = m_frame->GetSelectedComponentIndices();
bool firstAssoc = true;
for( auto i : sel )
{
CVPCB_ASSOCIATION newfp( i, fpid );
m_frame->AssociateFootprint( newfp );
m_frame->AssociateFootprint( newfp, firstAssoc );
firstAssoc = false;
}
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()
{
// Update the menu
Go( &CVPCB_CONTROL::UpdateMenu, ACTIONS::updateMenu.MakeEvent() );
// Run the footprint viewer
Go( &CVPCB_CONTROL::ShowFootprintViewer, CVPCB_ACTIONS::showFootprintViewer.MakeEvent() );
@ -189,6 +226,8 @@ void CVPCB_CONTROL::setTransitions()
Go( &CVPCB_CONTROL::ToPreviousNA, CVPCB_ACTIONS::gotoPreviousNA.MakeEvent() );
// 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::AutoAssociate, CVPCB_ACTIONS::autoAssociate.MakeEvent() );

View File

@ -41,6 +41,20 @@ public:
/// @copydoc TOOL_INTERACTIVE::Reset()
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.
*
@ -107,6 +121,13 @@ public:
*/
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.
*/