Browse Source

Added a setNormalisableRange method to Slider

tags/2021-05-28
Tom Poole 7 years ago
parent
commit
284fdc51df
3 changed files with 114 additions and 109 deletions
  1. +41
    -3
      modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp
  2. +67
    -106
      modules/juce_gui_basics/widgets/juce_Slider.cpp
  3. +6
    -0
      modules/juce_gui_basics/widgets/juce_Slider.h

+ 41
- 3
modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp View File

@@ -422,10 +422,48 @@ struct AudioProcessorValueTreeState::SliderAttachment::Pimpl : private Attached
: AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false) : AttachedControlBase (s, p), slider (sl), ignoreCallbacks (false)
{ {
NormalisableRange<float> range (s.getParameterRange (paramID)); 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())); slider.setDoubleClickReturnValue (true, range.convertFrom0to1 (param->getDefaultValue()));
sendInitialUpdate(); sendInitialUpdate();


+ 67
- 106
modules/juce_gui_basics/widgets/juce_Slider.cpp View File

@@ -103,45 +103,47 @@ public:
return 0.0f; 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 double getValue() const
@@ -423,26 +425,18 @@ public:
double constrainedValue (double value) const 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 float getLinearSliderPos (double value) const
{ {
double pos; double pos;
if (maximum <= minimum)
if (normRange.end <= normRange.start)
pos = 0.5; pos = 0.5;
else if (value < minimum)
else if (value < normRange.start)
pos = 0.0; pos = 0.0;
else if (value > maximum)
else if (value > normRange.end)
pos = 1.0; pos = 1.0;
else else
pos = owner.valueToProportionOfLength (value); pos = owner.valueToProportionOfLength (value);
@@ -475,13 +469,6 @@ public:
modifierToSwapModes = newModifierToSwapModes; modifierToSwapModes = newModifierToSwapModes;
} }
void setSkewFactorFromMidPoint (double sliderValueToShowAtMidPoint)
{
if (maximum > minimum)
skewFactor = std::log (0.5) / std::log ((sliderValueToShowAtMidPoint - minimum)
/ (maximum - minimum));
}
void setIncDecButtonsMode (IncDecButtonMode mode) void setIncDecButtonsMode (IncDecButtonMode mode)
{ {
if (incDecButtonMode != mode) if (incDecButtonMode != mode)
@@ -592,8 +579,8 @@ public:
owner.addAndMakeVisible (incButton.get()); owner.addAndMakeVisible (incButton.get());
owner.addAndMakeVisible (decButton.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) if (incDecButtonMode != incDecButtonsNotDraggable)
{ {
@@ -835,7 +822,7 @@ public:
{ {
mouseDoubleClick(); mouseDoubleClick();
} }
else if (maximum > minimum)
else if (normRange.end > normRange.start)
{ {
useDragEvents = true; useDragEvents = true;
@@ -871,7 +858,7 @@ public:
void mouseDrag (const MouseEvent& e) void mouseDrag (const MouseEvent& e)
{ {
if (useDragEvents && maximum > minimum
if (useDragEvents && normRange.end > normRange.start
&& ! ((style == LinearBar || style == LinearBarVertical) && ! ((style == LinearBar || style == LinearBarVertical)
&& e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable())) && e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable()))
{ {
@@ -892,7 +879,7 @@ public:
mouseDragStartPos = e.position; mouseDragStartPos = e.position;
} }
if (isAbsoluteDragMode (e.mods) || (maximum - minimum) / sliderRegionSize < interval)
if (isAbsoluteDragMode (e.mods) || (normRange.end - normRange.start) / sliderRegionSize < normRange.interval)
{ {
dragMode = absoluteDrag; dragMode = absoluteDrag;
handleAbsoluteDrag (e); handleAbsoluteDrag (e);
@@ -904,7 +891,7 @@ public:
} }
} }
valueWhenLastDragged = jlimit (minimum, maximum, valueWhenLastDragged);
valueWhenLastDragged = jlimit (normRange.start, normRange.end, valueWhenLastDragged);
if (sliderBeingDragged == 0) if (sliderBeingDragged == 0)
{ {
@@ -940,7 +927,7 @@ public:
{ {
if (owner.isEnabled() if (owner.isEnabled()
&& useDragEvents && useDragEvents
&& (maximum > minimum)
&& (normRange.end > normRange.start)
&& (style != IncDecButtons || incDecDragged)) && (style != IncDecButtons || incDecDragged))
{ {
restoreMouseIfHidden(); restoreMouseIfHidden();
@@ -1034,8 +1021,8 @@ public:
{ {
return doubleClickToValue return doubleClickToValue
&& style != IncDecButtons && style != IncDecButtons
&& minimum <= doubleClickReturnValue
&& maximum >= doubleClickReturnValue;
&& normRange.start <= doubleClickReturnValue
&& normRange.end >= doubleClickReturnValue;
} }
void mouseDoubleClick() void mouseDoubleClick()
@@ -1050,7 +1037,7 @@ public:
double getMouseWheelDelta (double value, double wheelAmount) double getMouseWheelDelta (double value, double wheelAmount)
{ {
if (style == IncDecButtons) if (style == IncDecButtons)
return interval * wheelAmount;
return normRange.interval * wheelAmount;
auto proportionDelta = wheelAmount * 0.15; auto proportionDelta = wheelAmount * 0.15;
auto currentPos = owner.valueToProportionOfLength (value); auto currentPos = owner.valueToProportionOfLength (value);
@@ -1069,7 +1056,7 @@ public:
{ {
lastMouseWheelTime = e.eventTime; lastMouseWheelTime = e.eventTime;
if (maximum > minimum && ! e.mods.isAnyMouseButtonDown())
if (normRange.end > normRange.start && ! e.mods.isAnyMouseButtonDown())
{ {
if (valueBox != nullptr) if (valueBox != nullptr)
valueBox->hideEditor (false); valueBox->hideEditor (false);
@@ -1080,7 +1067,7 @@ public:
* (wheel.isReversed ? -1.0f : 1.0f)); * (wheel.isReversed ? -1.0f : 1.0f));
if (delta != 0.0) 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); DragInProgress drag (*this);
setValue (owner.snapValue (newValue, notDragging), sendNotificationSync); setValue (owner.snapValue (newValue, notDragging), sendNotificationSync);
@@ -1242,9 +1229,9 @@ public:
ListenerList<Slider::Listener> listeners; ListenerList<Slider::Listener> listeners;
Value currentValue, valueMin, valueMax; Value currentValue, valueMin, valueMax;
double lastCurrentValue = 0, lastValueMin = 0, lastValueMax = 0; 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; double velocityModeSensitivity = 1.0, velocityModeOffset = 0, minMaxDiff = 0;
int velocityModeThreshold = 1; int velocityModeThreshold = 1;
RotaryParameters rotaryParams; RotaryParameters rotaryParams;
@@ -1426,19 +1413,18 @@ void Slider::setVelocityModeParameters (double sensitivity, int threshold,
userCanPressKeyToSwapMode, modifierToSwapModes); 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) 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) void Slider::setSkewFactorFromMidPoint (double sliderValueToShowAtMidPoint)
{ {
pimpl->setSkewFactorFromMidPoint (sliderValueToShowAtMidPoint);
pimpl->symmetricSkew = false;
pimpl->normRange.setSkewForCentre (sliderValueToShowAtMidPoint);
} }
int Slider::getMouseDragSensitivity() const noexcept { return pimpl->pixelsForFullDragExtent; } int Slider::getMouseDragSensitivity() const noexcept { return pimpl->pixelsForFullDragExtent; }
@@ -1490,13 +1476,14 @@ void Slider::lookAndFeelChanged() { pimpl->lookAndFeelChanged (getLookAndFeel(
void Slider::enablementChanged() { repaint(); pimpl->updateTextBoxEnablement(); } 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(); } double Slider::getValue() const { return pimpl->getValue(); }
Value& Slider::getValueObject() noexcept { return pimpl->currentValue; } Value& Slider::getValueObject() noexcept { return pimpl->currentValue; }
@@ -1574,38 +1561,12 @@ double Slider::getValueFromText (const String& text)
double Slider::proportionOfLengthToValue (double proportion) 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) 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) double Slider::snapValue (double attemptedValue, DragMode)


+ 6
- 0
modules/juce_gui_basics/widgets/juce_Slider.h View File

@@ -416,6 +416,12 @@ public:
*/ */
void setRange (Range<double> newRange, double newInterval); 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. */ /** Returns the slider's range. */
Range<double> getRange() const noexcept; Range<double> getRange() const noexcept;


Loading…
Cancel
Save