I am creating a Viewport that allows its contained component to be zoomed. Eventually I will probably control the zoom with gestures, but for now I am using a Slider since JUCE does not natively support pinch gestures on iOS (please let me know if I’m wrong about this!). Currently, I have a Parameter in my APVTS called “viewportZoomScaleFactor”; I have a struct AttachedSlider that connects a Slider to that Parameter with a juce::AudioProcessorValueTreeState::SliderAttachment and also creates a ParameterAttachment, with the idea that the ParameterAttachment callback would update the zoom of the Viewport.
struct AttachedSlider
{
AttachedSlider(PitchPlanePluginAudioProcessor& p, juce::String paramID, std::function<void(float)> paramChangedCallback, juce::UndoManager* undoManager) :
sliderAttachment(p.getApvts(), paramID, slider),
parameterAttachment(*p.getApvts().getParameter(paramID), paramChangedCallback, undoManager)
{
slider.setSliderStyle(juce::Slider::RotaryVerticalDrag);
slider.setTextBoxStyle(juce::Slider::TextBoxBelow, false, slider.getTextBoxWidth(), slider.getTextBoxHeight());
}
juce::Slider slider;
juce::AudioProcessorValueTreeState::SliderAttachment sliderAttachment;
juce::ParameterAttachment parameterAttachment;
};
}
I define the ParameterAttachment callback and then instantiate an AttachedSlider:
std::function<void(float)> zoomCallback = [this] (float newValue)
{
float value = audioProcessor.getApvts().getRawParameterValue("viewportZoomScaleFactor")->load();
viewedComponent.setTransform(juce::AffineTransform::scale(value));
viewedComponentContainer.setBounds(playSurface.getBoundsInParent());
DBG("ZOOM: " << value);
};
AttachedSlider zoomSlider { audioProcessor, "viewportZoomScaleFactor", zoomCallback, nullptr };
I did it this way because I thought it made more sense for the Viewport to be attached to the actual Parameter, rather than to respond to onSliderValueChanged, but I’m wondering if I’ve overcomplicated everything. Also I am aware that I could have the ParameterAttachment be a member of the Viewport rather than part of the AttachedSlider struct, this was just a quicker way for me to test this for now. Anyway, the Viewport zooms almost as expected. On to the problems:
- It seems that the ParameterAttachment callback happens before the most recent Parameter value is updated. So my Viewport is always zoomed according to the penultimate Parameter value, rather than the current value. I tried looking at the ParameterAttachment code but I haven’t figured out exactly how the paramChangedCallback is triggered there.
- Would it be simpler to have SliderValueChanged() trigger the Viewport zoom functions? Since the Slider and Parameter are attached, a Parameter change would update the Slider, which would then update the Viewport. The issue I’m considering is if I have a view in which the Slider isn’t present, but I still want the Viewport to zoom in response to DAW automation, are there potential problems?
- Maybe part of the problem is the ParameterAttachment::setValueAsCompleteGesture versus continuous gestures? Do I need to incorporate startGesture() and endGesture() in some way?
- Within the ParameterAttachment callback std::function, I’m not sure what the input float argument is. Does the ParameterAttachment automatically call the callback with the updated Parameter value somehow? Again, I did look at the juce code but I’m struggling to understand how the callback is instantiated/implemented.
Thanks for any help!
