Hi all
I thought I would post this here since the title of the thread is still applicable to my new issue.
I have my plugin working perfectly using the AudioProcessorValueTreeState class, and am trying to implement undo/redo behaviour. I have come very close to getting it to work, but the bahaviour is very erratic and after days spent trying to debug, my last resort is to reach out for some assistance.
I am managing undo behaviour from my editor class. It seems that the UndoManager perform() method is called after (most) undo actions. To give a simplified example of a slider, this is basically what I am doing:
In order to separate transactions, when a slider drag ends I start a timer:
void sliderDragEnded (Slider* /*slider*/)
{
startTimer(500);
}
When the timer callback is called, I call beginNewTransaction().
void timerCallback()
{
myProcessor->pluginState.undoManager->beginNewTransaction();
stopTimer();
}
I have undo and redo buttons that act as follows:
void buttonClicked (Button* button)
{
if (button == undoButton)
{
if (myProcessor->pluginState.undoManager->canUndo())
myProcessor->pluginState.undoManager->undo();
}
if (button == redoButton)
{
if (myProcessor->pluginState.undoManager->canRedo())
myProcessor->pluginState.undoManager->redo();
}
}
In the event that I now call undo() from a button on the GUI, the AudioProcessorValueTreeState::setValue() method is called, which (as far as I can figure out) in turn calls the setProperty method, which then calls the perform() method.
void setProperty (const Identifier& name, const var& newValue, UndoManager* const undoManager)
{
if (undoManager == nullptr)
{
if (properties.set (name, newValue))
sendPropertyChangeMessage (name);
}
else
{
if (const var* const existingValue = properties.getVarPointer (name))
{
if (*existingValue != newValue)
undoManager->perform (new SetPropertyAction (this, name, newValue, *existingValue, false, false));
}
else
{
--> undoManager->perform (new SetPropertyAction (this, name, newValue, var(), true, false));
}
}
}
So it seems that the undo() method recursively calls perform() which is specifically warned against in the UndoableAction documentation. This prevents the corresponding redo() action from being called and leads to a lot of strange behaviour.
I am not sure how to prevent this recursive call to perform() when an undo action is done. Am I using the UndoManager in the correct way with AudioProcessorValueTreeState, or am I doing something blatantly silly?
My guess is the contributors to this thread are encountering the same issue, see towards the end: AudioProcessorValueTreeState & UndoManager usage)
