Help a newbie: 2D Slider (x/y controller)


#1

Hi fellas, a JUCE newbie here.

I have a small VST plugin with two parameters (“x” and “y”) of type AudioParameterFloat.

Currently, these are controlled by two simple sliders on the plugin’s editor.

Now I would like to pimp my plugin’s GUI out by adding a “2D slider”, or I guess some people would call it “X/Y controller”. Note that I would like to keep my sliders, in case only X or only Y wants to be modified. The “2D slider” should allow you to change X and Y simultaneously.

That’s part of my problem, I don’t even know what such a thing is called and thus have trouble googling for a solution on how to implement it in JUCE. Here is a mockup I made of how the thing is supposed to look like.

Can someone point me in the general direction on how to implement this?

Appreciate your help.


#2

Hi Burns,

I don’t think, it exists out of the box. however, it shouldn’t be too hard.
You inherit Component and override mouseDown (const MouseEvent& event), mouseDrag() and paint().

Give it a reference or pointer to the processor, so it can call setValue on the parameter you want to attach to.

To paint the knob you can get inspiration on the LookAndFeel:

Hope that helps


#3

Hi Daniel,

perfect, that will get me started!

I’ll post back when I got some progress.

Thank you!


#4

Hi There,

Exactly.
I did something quite similar not long ago and I would like to add that if you want to keep your sliders I’d recommend not using the xy controller to change the value, but to change the sliders instead, then the sliders will change the value as if they were moved by the user.
You can use the “ActionBroadcaster” to send messages from the xy to the pluginEditor.
Must say that I’m pretty newbie myself, so if anyone has a better way then the “ActionBroadcaster” I’d love to hear it.


#5

I wouldn’t do that. Best practice is to have one place where the value is stored, and multiple views may display that value.
So your Sliders will be attached with SliderAttachments to the parameters, and for the XY controller you do this by hand, making it a parameterListener listening for the x and the y parameter. That way all controls show the correct value, no matter which knob changed the parameter.
This is called a “Subject-Observer pattern”, a simplification to the “Model-View-Controller pattern”.

This is not needed here, because the Parameter classes are designed to transfer the changes from the GUI thread (MessageManager) to the AudioProcessor / AudioThread.

If you still want to set the slider value from the XY component, make sure to use dontSendNotification when reacting to changes from the prameter, so you don’t send notifications in a circle. But it’s way easier to communicate with the processor only.


#6

Top tip: Best way to do this would be with two Value objects that hold the X and Y, and connect them to both the individual and 2-axis slider components


#7

You guys are great, thank you for all the ideas.

Now I just need the time to try it out! I’ll let you know as soon as I’ve made some progress.


#8

What do you exactly mean by “connect them”?

Currently, my editor inherits from Slider::Listener and does this in it’s constructor:

x_slider->addListener(this);
y_slider->addListener(this);
addAndMakeVisible(x_slider);
addAndMakeVisible(y_slider);

#9

Have a look at how the sliders in the demo app are done:


#10

Hi again,

Okay, so I’ve got my sliders moving whenever I drag my 2D-Slider’s knob. I achieved this by having my 2D-Slider’s X and Y Value objects referTo the Value objects in my Editor, like Jules suggested.

My 2D-Slider’s mouseDown and mouseDrag methods set the value of the two AudioProcessorParameter in my AudioProcessor directly.

Now I need to get the other direction working as well: get the 2D-Slider’s knob to move when I move the individual sliders.

If I understand this correctly, it contradicts what I was about to do:
I would make an abstract Listener sub-class nested in my 2D-Slider class; then inherit my Editor from 2DSlider::Listener, and finally implement there the knobValueChanged, knobDragStarted and knobDragEnded methods, just like I did with the regular Sliders.


#11

If your 2D-Sliders paint method uses the coordinates from the value objects, maybe you only need a repaint() whenever one of the two value objects change…?

Make the 2D-Slider a Value::Listener and add it to the two Value objects. Then simply override the

void 2D-Slider::valueChanged (Value &value) override { repaint(); }

#12

Works! That’s much simpler than what I was about to do. :slight_smile:

Thank you!