Rotary VerticalDrag/HorizontalDrag bug


When holding CTRL (to increase adjustment precision) while turning a Rotary VerticalDrag/HorizontalDrag Slider and then releasing CTRL without releasing the mouse button, the Slider jumps back to a position near the one it had when the mouse button was initially pressed to start turning.

Shouldn’t the Slider stay in position just as it is the case for the Linear-type Sliders?


Seems to work fine for me…?


?? When I’m in Jucer and I add a new Rotary VerticalDrag Slider, and press CTRL while turning and release while the mouse button is still down, the Slider suddenly jumps to a previous position. Is that not the case on your computer?


I can reproduce the behavior zamrate describes with the precompiled Jucer binary for Windows.


Listen, there’s a bug, really. Not only in the JUCER, but also when I use a rotary slider in my app.

First turn the slider a bit without CTRL, still hold the mouse button down, press CTRL and continue turning, then while still holding the mouse button down, release CTRL and continue turning.

You will notice a jump in the position that should just not be. I remember that this was one of the reasons why I wrote my own “Knob” class.


The jump comes from the incorrect mouse position restoring in Slider::restoreMouseIfHidden, when you release the velocity mode key, here’s a solution for it:

First, two new varaibles for the Silder class (juce_Slider.h):

[code] float rotaryStart, rotaryEnd;
int numDecimalPlaces, mouseXWhenLastDragged, mouseYWhenLastDragged;

  • int mouseXWhenLastDown, mouseYWhenLastDown;
    int sliderRegionStart, sliderRegionSize;
    int sliderBeingDragged;[/code]

Second, store the last mouse down position in Slider::mouseDown (juce_Slider.cpp):

[code] minMaxDiff = valueMax - valueMin;

        mouseXWhenLastDragged = e.x;
        mouseYWhenLastDragged = e.y;
  •       mouseXWhenLastDown = e.x;
  •       mouseYWhenLastDown = e.y;
          lastAngle = rotaryStart + (rotaryEnd - rotaryStart)
                                      * valueToProportionOfLength (currentValue);
          if (sliderBeingDragged == 2)
              valueWhenLastDragged = valueMax;[/code]

Third, the changed Slider::restoreMouseIfHidden (juce_Slider.cpp) to restore the mouse position for rotary drag sliders correct:

[code]void Slider::restoreMouseIfHidden()
if (mouseWasHidden)
mouseWasHidden = false;

    Component* c = Component::getComponentUnderMouse();

    if (c == 0)
        c = this;

    c->enableUnboundedMouseMovement (false);

    const double pos = (sliderBeingDragged == 2) ? getMaxValue()
                                                 : ((sliderBeingDragged == 1) ? getMinValue()
                                                                              : currentValue);
  •   if (style == RotaryHorizontalDrag || style == RotaryVerticalDrag)
  •   {
  •       int x, y, dummy;
  •       double posDiff;
  •       Desktop::getMousePosition (x, y);
  •       if (style == RotaryHorizontalDrag)
  •       {
  •           posDiff = valueToProportionOfLength (pos) - valueToProportionOfLength (valueOnMouseDown);
  •           x = pixelsForFullDragExtent * posDiff + mouseXWhenLastDown;
  •           relativePositionToGlobal (x, dummy);
  •       }
  •       else
  •       {
  •           posDiff = valueToProportionOfLength (valueOnMouseDown) - valueToProportionOfLength (pos);
  •           y = pixelsForFullDragExtent * posDiff + mouseYWhenLastDown;
  •           relativePositionToGlobal (dummy, y);
  •       }
  •       Desktop::setMousePosition (x, y);
  •   }
  •   else
  •   {
          const int pixelPos = (int) getLinearSliderPos (pos);
          int x = isHorizontal() ? pixelPos : (getWidth() / 2);
          int y = isVertical()   ? pixelPos : (getHeight() / 2);
          relativePositionToGlobal (x, y);
          Desktop::setMousePosition (x, y);
  •   }


Ah, I see. I misunderstood what you were saying the first time. Ok, that’s worth fixing - thanks for the help, chaps, I’ll check something in shortly…