Undo manager is not attached to AudioProcessorValueTreeState

Hi, in my processor.h I created my AudioProcessorValueTreeState and my UndoManager, after I initialized it with like this:

[...]
parametersState(*this, &undoManager, Identifier(getName()), createParameterLayout())
#endif
{
    undoManager.clearUndoHistory();
    parametersState.state = ValueTree(ayra::IDs::TRACK);
}

AudioProcessorValueTreeState::ParameterLayout NodeGraph_PluginAudioProcessor::createParameterLayout()
{
    AudioProcessorValueTreeState::ParameterLayout result;
    result.add(std::make_unique<AudioParameterBool>(ParameterID { "shutdown", 1 }, "shutdown", false));    
    return result;
}

In my editor I have this:

    shutdownBtn.onClick = [this]()
    {
        bool shutdown = audioProcessor.parametersState.getParameter("shutdown")->getValue();
        audioProcessor.parametersState.getParameter("shutdown")->setValue(!shutdown);
        doStuff(!shutdown);
    };
    
    undoBtn.onClick = [this]() { audioProcessor.undoManager.undo(); };
    redoBtn.onClick = [this]() { audioProcessor.undoManager.redo(); };

but when I click on undo/redo nothing happens… there’s something I’m missing?

None can help me?

Just calling setValue on a parameter isn’t enough to add a transaction to the UndoManager.

If you’re using SliderParameterAttachment or the other non-APVTS ParameterAttachments, you can pass an undo manager into the constructor of the attachment. UndoManager::beginNewTransaction will then be called automatically at the start of each parameter change gesture. If you’re using the APVTS attachments, you don’t even need to remember to pass in the undomanager.

If you’re not using attachments, then you’ll need to make sure to call beginNewTransaction before each parameter change.

1 Like

really thank you!

I added this line of code

        audioProcessor.undoManager.beginNewTransaction();

before this one

        audioProcessor.parametersState.getParameter("shutdown")->setValue(!shutdown);

but again it doesn’t works…

setValue() is the method the host calls from automation. When the GUI wants to change a value, it should call setValueNotifyingHost().
The reason for that detour is, that the host has the final say if a parameter change is applied or rejected, due to automation settings, like “Read”.

I hope the APVTS will pick it up then.
There is an internal method running from a timer, flushParameterValuesToValueTree() which should take care of setting the change to the UndoManager.

N.B. there is also an AudioProcessorValueTreeState::ButtonAttachment, which implements the toggle behaviour. You just need to set the button with setClickingTogglesState().

2 Likes

Finally I used the button attachment, it works now, there’s only a strange bug, the first click on each button attached to a parameter is not counted from the undo manager… I don’t know…

hi, sorry, but this is going me mad…

I have and undoManager instance on my AudioProcessor, after I pass it in constructor of my AudioProcessorValueTreeState.

in my AudioProcessor I have implemented parameterChanged( const String& parameterID, float newValue) to update components in my AudioProcessorEditor.

In my AudioProcessorEditor I have some buttons attached to params with “Attachments”, here an example:

addAndMakeVisible(lockBtn);
lockAttachment.reset (new ButtonAttachment (audioProcessor.parametersState, "lock", lockBtn));
lockBtn.setToggleable(true);
lockBtn.setClickingTogglesState(true);
lockBtn.setTooltip("Lock interactions with GUI Interface");

The bug is: at the first time the parameters changed undo manager doesn’t take care of the change:
For example → I have a button attached to a param, I click on this button for the first time and after I click on undoButton (nothing happens), then I click again on button attached to param and now clicking on undoButton undo works (but the first change is still forget)…

Make sure to setup the button before the attachment.
When you create the attachment it applies the state, but at that point the button is not yet togglable.

1 Like

I moved this line of code
lockAttachment.reset (new ButtonAttachment (audioProcessor.parametersState, "lock", lockBtn));
to the bottom of the AudioProcessorEditor constructor, but it doesn’t solve the problem…