"Double ring" slider?

Hello, has by chance anyone done a “double ring” rotary slider? I mean 2 sliders, that take up the space of one - with an inner and an outer slider?

I have been thinking about creating one myself, based on a class that has 2 std Juce sliders, and do the look & feel myself - but there’s SO much to the slider class (and the its L&F) I’m wondering how much time & effort that would take me. Then again I could just implement the bare minimum I would need … but perhaps anyone has done anything like that already?

No takers/reactions? Must be I’m the only one with a need for this. I’ll probably try & make such a Juce component myself - will post back here when done but it’s definitely on the back burner for now.

Maybe lookAndFeel a two or three value style slider ?

I thought of that but I doubt that’ll work: I need the 2 rings to be able to move totally independently. In a standard 2 value slider you can’t have the “lowest” value be higher then the “highest”. But I might take the 2 value slider class as a basis for my own ‘2 ring class’.

The other reason against is the lack of a SliderAttachment, that can connect two AudioParameterFloats from AudioProcessorValueTreeState to the two values of the slider…

It might be the easiest to write a class, that aggregates two sliders and keep the drawing completely separate, or roll from scratch, including a SliderAttachment, that takes two parameters to connect to…

1 Like

start with inheriting a slider, then you’ll basically need to do some math and manage their behavior with
juce::Component::hitTest(int x, int y)

1 Like

seems like a pair of standard rotary sliders who have their centers at the same location, but the outer one having a width/height be 25% larger than the inner would do the trick. Add the larger slider first to your component, and add the smaller one second. Maybe I’m oversimplifying though…


    outer.setColour(Slider::ColourIds::backgroundColourId, Colours::white);
    inner.setColour(Slider::ColourIds::backgroundColourId, Colours::green.withAlpha(0.1f));


    outer.setSize(250, 250);
    inner.setSize(200, 200);
    inner.setTopLeftPosition(25, 25);
///the default LNF for rotary slider doesn't `fillAll()`...
class SliderLNF : public LookAndFeel_V4
    void drawRotarySlider (Graphics& g, int x, int y, int width, int height, float sliderPos,
                                           const float rotaryStartAngle, const float rotaryEndAngle, Slider& slider) override

        auto c = slider.findColour(Slider::Slider::ColourIds::backgroundColourId);
        DBG( "bkgd color: " << c.toString() );
        LookAndFeel_V4::drawRotarySlider(g, x, y, width, height, sliderPos, rotaryStartAngle, rotaryEndAngle, slider);
    SliderLNF lnf;
    Slider inner{Slider::SliderStyle::Rotary, Slider::TextEntryBoxPosition::NoTextBox };
    Slider outer{Slider::SliderStyle::Rotary, Slider::TextEntryBoxPosition::NoTextBox };

you definitely need to override the hitTest, because the inner blocks mouse events from reaching the outer in the corners where they overlap.

it does work, though…

1 Like

It seems that this kind of thing comes up every so often when users are creating custom controls. I know I’ve rolled my own Attachment classes a few times for my own custom controls. I usually start with either the Button or Slider Attachment class, copy it, and hack away until it fits my use case.

Based on that, I’m wondering if JUCE shouldn’t have an abstract Attachment class so we could be a bit more proper and safe when attaching our own custom controls.


That great and much appreciated! Bit funny - I was thinking about something along that line last night - you were probably trying it while I was entertaining the same idea in my head! I’ll give that approach a shot.

Excellent, a lot of plugins use double rotary sliders, this could be an interesting addition for Juce, don’t you think?

1 Like

I think that is a great idea, I was thinking something similar.
For instance, it would be possible to create a Value attachment, or even better, a class similar to Value, which is using the NormalisedRange…

But that all can be done without any changes for the JUCE base (the Attachment can be an AudioProcessorParameter::Listener and listen to the Component or multiple instances could be aggregated for a use case like the one mentioned…)


+1 for that! Especially the AttachedControlBase, as I had to create a copy of that to make it accessible for my LabelAttachment.

1 Like