Skip to content

Commit

Permalink
Added a setNormalisableRange method to Slider
Browse files Browse the repository at this point in the history
  • Loading branch information
tpoole committed Mar 2, 2018
1 parent 3fae666 commit 284fdc5
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 109 deletions.
Expand Up @@ -422,10 +422,48 @@ struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private Attached
: AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false)
{
NormalisableRange<float> range (s.getParameterRange (paramID));
slider.setRange (range.start, range.end, range.interval);
slider.setSkewFactor (range.skew, range.symmetricSkew);

if (AudioProcessorParameter* param = state.getParameter (paramID))
if (range.interval != 0 || range.skew != 0)
{
slider.setRange (range.start, range.end, range.interval);
slider.setSkewFactor (range.skew, range.symmetricSkew);
}
else
{
auto convertFrom0To1Function = [range] (double currentRangeStart,
double currentRangeEnd,
double normalisedValue) mutable
{
range.start = (float) currentRangeStart;
range.end = (float) currentRangeEnd;
return (double) range.convertFrom0to1 ((float) normalisedValue);
};

auto convertTo0To1Function = [range] (double currentRangeStart,
double currentRangeEnd,
double mappedValue) mutable
{
range.start = (float) currentRangeStart;
range.end = (float) currentRangeEnd;
return (double) range.convertTo0to1 ((float) mappedValue);
};

auto snapToLegalValueFunction = [range] (double currentRangeStart,
double currentRangeEnd,
double valueToSnap) mutable
{
range.start = (float) currentRangeStart;
range.end = (float) currentRangeEnd;
return (double) range.snapToLegalValue ((float) valueToSnap);
};

slider.setNormalisableRange ({ (double) range.start, (double) range.end,
convertFrom0To1Function,
convertTo0To1Function,
snapToLegalValueFunction });
}

if (auto* param = state.getParameter (paramID))
slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue()));

sendInitialUpdate();
Expand Down
173 changes: 67 additions & 106 deletions modules/juce_gui_basics/widgets/juce_Slider.cpp
Expand Up @@ -103,45 +103,47 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
return 0.0f;
}

void setRange (double newMin, double newMax, double newInt)
void updateRange()
{
if (minimum != newMin || maximum != newMax || interval != newInt)
{
minimum = newMin;
maximum = newMax;
interval = newInt;

// figure out the number of DPs needed to display all values at this
// interval setting.
numDecimalPlaces = 7;
// figure out the number of DPs needed to display all values at this
// interval setting.
numDecimalPlaces = 7;

if (newInt != 0.0)
{
int v = std::abs (roundToInt (newInt * 10000000));

if (v > 0)
{
while ((v % 10) == 0)
{
--numDecimalPlaces;
v /= 10;
}
}
}
if (normRange.interval != 0.0)
{
int v = std::abs (roundToInt (normRange.interval * 10000000));

// keep the current values inside the new range..
if (style != TwoValueHorizontal && style != TwoValueVertical)
{
setValue (getValue(), dontSendNotification);
}
else
while ((v % 10) == 0)
{
setMinValue (getMinValue(), dontSendNotification, false);
setMaxValue (getMaxValue(), dontSendNotification, false);
--numDecimalPlaces;
v /= 10;
}
}

updateText();
// keep the current values inside the new range..
if (style != TwoValueHorizontal && style != TwoValueVertical)
{
setValue (getValue(), dontSendNotification);
}
else
{
setMinValue (getMinValue(), dontSendNotification, false);
setMaxValue (getMaxValue(), dontSendNotification, false);
}

updateText();
}

void setRange (double newMin, double newMax, double newInt)
{
normRange = NormalisableRange<double> (newMin, newMax, newInt);
updateRange();
}

void setNormalisableRange (NormalisableRange<double> newRange)
{
normRange = newRange;
updateRange();
}

double getValue() const
Expand Down Expand Up @@ -423,26 +425,18 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis

double constrainedValue (double value) const
{
if (interval > 0)
value = minimum + interval * std::floor ((value - minimum) / interval + 0.5);

if (value <= minimum || maximum <= minimum)
value = minimum;
else if (value >= maximum)
value = maximum;

return value;
return normRange.snapToLegalValue (value);
}

float getLinearSliderPos (double value) const
{
double pos;

if (maximum <= minimum)
if (normRange.end <= normRange.start)
pos = 0.5;
else if (value < minimum)
else if (value < normRange.start)
pos = 0.0;
else if (value > maximum)
else if (value > normRange.end)
pos = 1.0;
else
pos = owner.valueToProportionOfLength (value);
Expand Down Expand Up @@ -475,13 +469,6 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
modifierToSwapModes = newModifierToSwapModes;
}

void setSkewFactorFromMidPoint (double sliderValueToShowAtMidPoint)
{
if (maximum > minimum)
skewFactor = std::log (0.5) / std::log ((sliderValueToShowAtMidPoint - minimum)
/ (maximum - minimum));
}

void setIncDecButtonsMode (IncDecButtonMode mode)
{
if (incDecButtonMode != mode)
Expand Down Expand Up @@ -592,8 +579,8 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
owner.addAndMakeVisible (incButton.get());
owner.addAndMakeVisible (decButton.get());

incButton->onClick = [this] { incrementOrDecrement (interval); };
decButton->onClick = [this] { incrementOrDecrement (-interval); };
incButton->onClick = [this] { incrementOrDecrement (normRange.interval); };
decButton->onClick = [this] { incrementOrDecrement (-normRange.interval); };

if (incDecButtonMode != incDecButtonsNotDraggable)
{
Expand Down Expand Up @@ -835,7 +822,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
{
mouseDoubleClick();
}
else if (maximum > minimum)
else if (normRange.end > normRange.start)
{
useDragEvents = true;

Expand Down Expand Up @@ -871,7 +858,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis

void mouseDrag (const MouseEvent& e)
{
if (useDragEvents && maximum > minimum
if (useDragEvents && normRange.end > normRange.start
&& ! ((style == LinearBar || style == LinearBarVertical)
&& e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable()))
{
Expand All @@ -892,7 +879,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
mouseDragStartPos = e.position;
}

if (isAbsoluteDragMode (e.mods) || (maximum - minimum) / sliderRegionSize < interval)
if (isAbsoluteDragMode (e.mods) || (normRange.end - normRange.start) / sliderRegionSize < normRange.interval)
{
dragMode = absoluteDrag;
handleAbsoluteDrag (e);
Expand All @@ -904,7 +891,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
}
}

valueWhenLastDragged = jlimit (minimum, maximum, valueWhenLastDragged);
valueWhenLastDragged = jlimit (normRange.start, normRange.end, valueWhenLastDragged);

if (sliderBeingDragged == 0)
{
Expand Down Expand Up @@ -940,7 +927,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
{
if (owner.isEnabled()
&& useDragEvents
&& (maximum > minimum)
&& (normRange.end > normRange.start)
&& (style != IncDecButtons || incDecDragged))
{
restoreMouseIfHidden();
Expand Down Expand Up @@ -1034,8 +1021,8 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
{
return doubleClickToValue
&& style != IncDecButtons
&& minimum <= doubleClickReturnValue
&& maximum >= doubleClickReturnValue;
&& normRange.start <= doubleClickReturnValue
&& normRange.end >= doubleClickReturnValue;
}

void mouseDoubleClick()
Expand All @@ -1050,7 +1037,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
double getMouseWheelDelta (double value, double wheelAmount)
{
if (style == IncDecButtons)
return interval * wheelAmount;
return normRange.interval * wheelAmount;

auto proportionDelta = wheelAmount * 0.15;
auto currentPos = owner.valueToProportionOfLength (value);
Expand All @@ -1069,7 +1056,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
{
lastMouseWheelTime = e.eventTime;

if (maximum > minimum && ! e.mods.isAnyMouseButtonDown())
if (normRange.end > normRange.start && ! e.mods.isAnyMouseButtonDown())
{
if (valueBox != nullptr)
valueBox->hideEditor (false);
Expand All @@ -1080,7 +1067,7 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
* (wheel.isReversed ? -1.0f : 1.0f));
if (delta != 0.0)
{
auto newValue = value + jmax (interval, std::abs (delta)) * (delta < 0 ? -1.0 : 1.0);
auto newValue = value + jmax (normRange.interval, std::abs (delta)) * (delta < 0 ? -1.0 : 1.0);

DragInProgress drag (*this);
setValue (owner.snapValue (newValue, notDragging), sendNotificationSync);
Expand Down Expand Up @@ -1242,9 +1229,9 @@ class Slider::Pimpl : public AsyncUpdater, // this needs to be public otherwis
ListenerList<Slider::Listener> listeners;
Value currentValue, valueMin, valueMax;
double lastCurrentValue = 0, lastValueMin = 0, lastValueMax = 0;
double minimum = 0, maximum = 10, interval = 0, doubleClickReturnValue = 0;
double valueWhenLastDragged = 0, valueOnMouseDown = 0, skewFactor = 1.0, lastAngle = 0;
bool symmetricSkew = false;
NormalisableRange<double> normRange { 0.0, 10.0 };
double doubleClickReturnValue = 0;
double valueWhenLastDragged = 0, valueOnMouseDown = 0, lastAngle = 0;
double velocityModeSensitivity = 1.0, velocityModeOffset = 0, minMaxDiff = 0;
int velocityModeThreshold = 1;
RotaryParameters rotaryParams;
Expand Down Expand Up @@ -1426,19 +1413,18 @@ void Slider::setVelocityModeParameters (double sensitivity, int threshold,
userCanPressKeyToSwapMode, modifierToSwapModes);
}

double Slider::getSkewFactor() const noexcept { return pimpl->skewFactor; }
bool Slider::isSymmetricSkew() const noexcept { return pimpl->symmetricSkew; }
double Slider::getSkewFactor() const noexcept { return pimpl->normRange.skew; }
bool Slider::isSymmetricSkew() const noexcept { return pimpl->normRange.symmetricSkew; }

void Slider::setSkewFactor (double factor, bool symmetricSkew)
{
pimpl->skewFactor = factor;
pimpl->symmetricSkew = symmetricSkew;
pimpl->normRange.skew = factor;
pimpl->normRange.symmetricSkew = symmetricSkew;
}

void Slider::setSkewFactorFromMidPoint (double sliderValueToShowAtMidPoint)
{
pimpl->setSkewFactorFromMidPoint (sliderValueToShowAtMidPoint);
pimpl->symmetricSkew = false;
pimpl->normRange.setSkewForCentre (sliderValueToShowAtMidPoint);
}

int Slider::getMouseDragSensitivity() const noexcept { return pimpl->pixelsForFullDragExtent; }
Expand Down Expand Up @@ -1490,13 +1476,14 @@ void Slider::lookAndFeelChanged() { pimpl->lookAndFeelChanged (getLookAndFeel(
void Slider::enablementChanged() { repaint(); pimpl->updateTextBoxEnablement(); }

//==============================================================================
Range<double> Slider::getRange() const noexcept { return { pimpl->minimum, pimpl->maximum }; }
double Slider::getMaximum() const noexcept { return pimpl->maximum; }
double Slider::getMinimum() const noexcept { return pimpl->minimum; }
double Slider::getInterval() const noexcept { return pimpl->interval; }
Range<double> Slider::getRange() const noexcept { return { pimpl->normRange.start, pimpl->normRange.end }; }
double Slider::getMaximum() const noexcept { return pimpl->normRange.end; }
double Slider::getMinimum() const noexcept { return pimpl->normRange.start; }
double Slider::getInterval() const noexcept { return pimpl->normRange.interval; }

void Slider::setRange (double newMin, double newMax, double newInt) { pimpl->setRange (newMin, newMax, newInt); }
void Slider::setRange (Range<double> newRange, double newInt) { pimpl->setRange (newRange.getStart(), newRange.getEnd(), newInt); }
void Slider::setRange (double newMin, double newMax, double newInt) { pimpl->setRange (newMin, newMax, newInt); }
void Slider::setRange (Range<double> newRange, double newInt) { pimpl->setRange (newRange.getStart(), newRange.getEnd(), newInt); }
void Slider::setNormalisableRange (NormalisableRange<double> newRange) { pimpl->setNormalisableRange (newRange); }

double Slider::getValue() const { return pimpl->getValue(); }
Value& Slider::getValueObject() noexcept { return pimpl->currentValue; }
Expand Down Expand Up @@ -1574,38 +1561,12 @@ double Slider::getValueFromText (const String& text)

double Slider::proportionOfLengthToValue (double proportion)
{
auto skew = getSkewFactor();

if (! isSymmetricSkew())
{
if (skew != 1.0 && proportion > 0.0)
proportion = std::exp (std::log (proportion) / skew);

return getMinimum() + (getMaximum() - getMinimum()) * proportion;
}

double distanceFromMiddle = 2.0 * proportion - 1.0;

if (skew != 1.0 && distanceFromMiddle != 0.0)
distanceFromMiddle = std::exp (std::log (std::abs (distanceFromMiddle)) / skew)
* (distanceFromMiddle < 0 ? -1 : 1);

return getMinimum() + (getMaximum() - getMinimum()) / 2.0 * (1 + distanceFromMiddle);
return pimpl->normRange.convertFrom0to1 (proportion);
}

double Slider::valueToProportionOfLength (double value)
{
auto n = (value - getMinimum()) / (getMaximum() - getMinimum());
auto skew = getSkewFactor();

if (skew == 1.0)
return n;

if (! isSymmetricSkew())
return std::pow (n, skew);

double distanceFromMiddle = 2.0 * n - 1.0;
return (1.0 + std::pow (std::abs (distanceFromMiddle), skew) * (distanceFromMiddle < 0 ? -1 : 1)) / 2.0;
return pimpl->normRange.convertTo0to1 (value);
}

double Slider::snapValue (double attemptedValue, DragMode)
Expand Down
6 changes: 6 additions & 0 deletions modules/juce_gui_basics/widgets/juce_Slider.h
Expand Up @@ -416,6 +416,12 @@ class JUCE_API Slider : public Component,
*/
void setRange (Range<double> newRange, double newInterval);

/** Sets a NormalisableRange to use for the Slider values.
@param newNormalisableRange the NormalisableRange to use
*/
void setNormalisableRange (NormalisableRange<double> newNormalisableRange);

/** Returns the slider's range. */
Range<double> getRange() const noexcept;

Expand Down

0 comments on commit 284fdc5

Please sign in to comment.