Reverse Slider Direction

Hello,

I am trying to create a slider that will increase in value as the slider handle is dragged down (or left).  There doesn't appear to be any property I can set to do this, so I'm wondering if I need to go ahead and extend the Slider class to do this behavior or if there is an easier way?

Thanks,

Jason


#ifndef SLIDER_REVERSE_H
#define SLIDER_REVERSE_H
class Slider_reverse : public JUCE_NAMESPACE::Slider
{
public:
    Slider_reverse (const String& componentName): JUCE_NAMESPACE::Slider(componentName) {};
    ~Slider_reverse() {};
    double proportionOfLengthToValue (double proportion) {   return JUCE_NAMESPACE::Slider::proportionOfLengthToValue(1.0f-proportion);};
    double valueToProportionOfLength (double value) {   return 1.0f-(JUCE_NAMESPACE::Slider::valueToProportionOfLength(value)); };    
};
#endif // SLIDER_REVERSE_H


4 Likes

what about rotating the Slider by Pi using an AffineTransform around its centre?

The derived class worked perfectly.  I didn't noticed those methods when I was looking at the Slider class.

 

J

Rotating will make things such as text to look different. One wouldn’t want the text rotated…

You could also implement a custom lookandfeel for the Slider in which you change the way it paints. Benefit is that you don’t need to use a derived class.

Do you know where and how to implement this to a slider parameter listener?

Editor vs Processor side?

I ended up just throwing it in a custom slider class, works like a dream!

Thanks,

I have a few sliders, well knobs, which I would like to have reverse behavior, meaning dragging left will increase value, and dragging right will decrease.

I already have a custom LookandFeel class with a ‘drawRotarySlider’ function.

So looking at your above example code, which I can easily insert into my class or even function, but how do I actually specify that a particular knob/slider should behave in reverse?

As a side note, I am actually quite surprised that there seems not to be a JUCE reverse value option!?!

Since the NormalisableRange supports now lambdas for proportionForValue and vice versa, you can achieve that without overriding.
And if this is in a plugin, it’s best to specify that in the AudioProcessorParameter’s NormalisableRange, that you supply upon its creation. This will be propagated to the Slider via SliderAttachment to give a consistent behaviour in host views (automation/control surfaces) and the slider in your UI.

That wasn’t possible 2014, when this thread was created…

2 Likes

Ok great! Do you know of any online example of implementing this?

This is the constructor NormalisableRange.

auto range = NormalisableRange<double>(0.0, 100.0,
    [] (auto rangeStart, auto rangeEnd, auto normalised)
        { return rangeStart + (1.0 - normalised) * (rangeEnd - rangeStart); },
    [] (auto rangeStart, auto rangeEnd, auto value)
        { return 1.0 - (value - rangeStart) / (rangeEnd - rangeStart); },
    [] (auto rangeStart, auto rangeEnd, auto value)
        { return roundToInt (value); });

slider.setNormalisableRange (range);

or use the range in the AudioParameterFloat constructor.

N.B. the AudioParameterFloat uses NormalisableRange<float>, vs. the Slider uses NormalisableRange<double>.

If I did it right, this slider should go from 100 to 0 in integer steps…

EDIT: actually much easier to use jmap:

auto range = NormalisableRange<double>(0.0, 100.0,
    [] (auto rangeStart, auto rangeEnd, auto normalised)
        { return jmap (normalised, rangeEnd, rangeStart); },
    [] (auto rangeStart, auto rangeEnd, auto value)
        { return jmap (value, rangeEnd, rangeStart, 0.0, 1.0); },
    [] (auto rangeStart, auto rangeEnd, auto value)
        { return roundToInt (value); });
1 Like

Thanks a bunch, I’ll try it out right away!

Still however, it seems to be that one should just be able to specify a “simple” reverse slider setting.

I thought to remember to set a negative step to achieve that, but I must have dreamed that… it will not pass the asserts…

Agreed, it is always a difficult trade off between user convenience and keep the API small…

Not my say luckily :wink:

Your first example worked fine, but I had to setNumDecimalPlacesToDisplay(0), which I did not have to do before.

Now I’ll try your second solution.

Yep second example worked great too, still having to setNumDecimalPlacesToDisplay.

I had a look into the Slider code, the NormalisableRange has a member interval, that is used to figure out how many decimal places to display.
And I learned, that the snapToValue is optional, so you can simplify the example to

auto range = NormalisableRange<double>(0.0, 100.0,
    [] (auto rangeStart, auto rangeEnd, auto normalised)
        { return jmap (normalised, rangeEnd, rangeStart); },
    [] (auto rangeStart, auto rangeEnd, auto value)
        { return jmap (value, rangeEnd, rangeStart, 0.0, 1.0); });

range.interval = 1;
slider.setNormalisableRange (range);

That will display no numbers behind the decimal point.

@daniel
Awesome, thanks!