Slider fine adjustment by mouse wheel

I have searched for threads about this issue, but they seem rather old.

I’m pretty used to never drag sliders, but to use the mouse wheel. For me it is more ergonomic.

I’m seeing that Ctrl + mousewheel doesn’t change the precission as it does when dragging the slider. Is this implemented and has to be manually enabled or isn’t it possible?

A bit unrelated, but is there a way to change from ctrl to shift for the fine dragging modifier? Most of my plugin use shift, so I never remember.

2 Likes

hey,

mousewheel + sensitive drag and shift-mod for sensitive is actually one of my biggest issues with juce::Slider as well, which is why i started to figure out how knobs work myself at some point, so i can write my own subclass of component for that. in this video, that i released only a few weeks ago, i summarize my current approach for that.

the biggest issue with this approach is that you have to maintain the knob all by yourself. it won’t automatically get all the new features JUCE comes up with, like all this accessibility stuff lately. while i do think that’s a shame, i myself am not working in a big company yet, so i won’t get into accessibility yet anyway. but ultimatively i’d also suggest JUCE itself to just add mousewheel-sensitive-drag, as that’s really not a very hard thing to do and also more essential to workflow than accessibility as it just affects way more people. there are also some other things i’d like to see in juce::Slider that can be seen in my video but i’ll not mention them in this post, because i want this to stay on topic.

1 Like

I modified the Slider pimpl code…perhaps it’s something that could be done officially:

bool mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel)
    {
        if (scrollWheelEnabled
             && style != TwoValueHorizontal
             && style != TwoValueVertical)
        {
            // sometimes duplicate wheel events seem to be sent, so since we're going to
            // bump the value by a minimum of the interval, avoid doing this twice..
            if (e.eventTime != lastMouseWheelTime)
            {
                lastMouseWheelTime = e.eventTime;
            
                double dFactor = 1.0;
                
                if (isAbsoluteDragMode (e.mods) || (normRange.end - normRange.start) / sliderRegionSize < normRange.interval)
                {
                    dFactor = 1.0;
                }
                else
                {
                    dFactor = 0.25;
                }

                if (normRange.end > normRange.start && ! e.mods.isAnyMouseButtonDown())
                {
                    if (valueBox != nullptr)
                        valueBox->hideEditor (false);

                    auto value = static_cast<double> (currentValue.getValue());
                    auto delta = dFactor * getMouseWheelDelta (value, (std::abs (wheel.deltaX) > std::abs (wheel.deltaY)
                                                                  ? -wheel.deltaX : wheel.deltaY)
                                                               * (wheel.isReversed ? -1.0f : 1.0f));
                    if (delta != 0.0)
                    {
                        auto newValue = value + jmax (normRange.interval, std::abs (delta)) * (delta < 0 ? -1.0 : 1.0);

                        ScopedDragNotification drag (owner);
                        setValue (owner.snapValue (newValue, notDragging), sendNotificationSync);
                    }
                }
            }

            return true;
        }

        return false;
    }

Rail

3 Likes

Thanks to both. Let’s hope these land on mainline JUCE soon.

1 Like

That modification for the sensitivity seems pull request worthy. Has it been submitted? I could try myself.

In my case I went with a factor of 0.075

I made this quick and dirty class to snap the mouse wheel to a preset interval.

class SnappingSlider : public juce::Slider
{
public:
    SnappingSlider() :juce::Slider(){}
   ~SnappingSlider(){}

    void setSnappingVal(float val) noexcept { m_snapVal = val; };
    void mouseWheelMove(const juce::MouseEvent& e, const juce::MouseWheelDetails& wheel) override{
        juce::MouseWheelDetails w(wheel);
        w.deltaY = wheel.deltaY > 0 ? m_snapVal : -m_snapVal;
        Slider::mouseWheelMove(e, w);
    };

private:
    float m_snapVal{0.001f};

    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SnappingSlider)
};
5 Likes