|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615 |
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2013 - Raw Material Software Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found at: www.gnu.org/licenses
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
-
- ==============================================================================
- */
-
- class Slider::Pimpl : public AsyncUpdater,
- public ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
- public LabelListener,
- public ValueListener
- {
- public:
- Pimpl (Slider& s, SliderStyle sliderStyle, TextEntryBoxPosition textBoxPosition)
- : owner (s),
- style (sliderStyle),
- lastCurrentValue (0), lastValueMin (0), lastValueMax (0),
- minimum (0), maximum (10), interval (0), doubleClickReturnValue (0),
- skewFactor (1.0), velocityModeSensitivity (1.0),
- velocityModeOffset (0.0), velocityModeThreshold (1),
- rotaryStart (float_Pi * 1.2f),
- rotaryEnd (float_Pi * 2.8f),
- sliderRegionStart (0), sliderRegionSize (1), sliderBeingDragged (-1),
- pixelsForFullDragExtent (250),
- textBoxPos (textBoxPosition),
- numDecimalPlaces (7),
- textBoxWidth (80), textBoxHeight (20),
- incDecButtonMode (incDecButtonsNotDraggable),
- editableText (true),
- doubleClickToValue (false),
- isVelocityBased (false),
- userKeyOverridesVelocity (true),
- rotaryStop (true),
- incDecButtonsSideBySide (false),
- sendChangeOnlyOnRelease (false),
- popupDisplayEnabled (false),
- menuEnabled (false),
- useDragEvents (false),
- scrollWheelEnabled (true),
- snapsToMousePos (true),
- parentForPopupDisplay (nullptr)
- {
- }
-
- ~Pimpl()
- {
- currentValue.removeListener (this);
- valueMin.removeListener (this);
- valueMax.removeListener (this);
- popupDisplay = nullptr;
- }
-
- //==============================================================================
- void registerListeners()
- {
- currentValue.addListener (this);
- valueMin.addListener (this);
- valueMax.addListener (this);
- }
-
- bool isHorizontal() const noexcept
- {
- return style == LinearHorizontal
- || style == LinearBar
- || style == TwoValueHorizontal
- || style == ThreeValueHorizontal;
- }
-
- bool isVertical() const noexcept
- {
- return style == LinearVertical
- || style == LinearBarVertical
- || style == TwoValueVertical
- || style == ThreeValueVertical;
- }
-
- bool isRotary() const noexcept
- {
- return style == Rotary
- || style == RotaryHorizontalDrag
- || style == RotaryVerticalDrag
- || style == RotaryHorizontalVerticalDrag;
- }
-
- bool incDecDragDirectionIsHorizontal() const noexcept
- {
- return incDecButtonMode == incDecButtonsDraggable_Horizontal
- || (incDecButtonMode == incDecButtonsDraggable_AutoDirection && incDecButtonsSideBySide);
- }
-
- float getPositionOfValue (const double value) const
- {
- if (isHorizontal() || isVertical())
- return getLinearSliderPos (value);
-
- jassertfalse; // not a valid call on a slider that doesn't work linearly!
- return 0.0f;
- }
-
- void setRange (const double newMin, const double newMax, const double newInt)
- {
- 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;
-
- if (newInt != 0)
- {
- int v = std::abs (roundToInt (newInt * 10000000));
-
- while ((v % 10) == 0)
- {
- --numDecimalPlaces;
- v /= 10;
- }
- }
-
- // 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();
- }
- }
-
- double getValue() const
- {
- // for a two-value style slider, you should use the getMinValue() and getMaxValue()
- // methods to get the two values.
- jassert (style != TwoValueHorizontal && style != TwoValueVertical);
-
- return currentValue.getValue();
- }
-
- void setValue (double newValue, const NotificationType notification)
- {
- // for a two-value style slider, you should use the setMinValue() and setMaxValue()
- // methods to set the two values.
- jassert (style != TwoValueHorizontal && style != TwoValueVertical);
-
- newValue = constrainedValue (newValue);
-
- if (style == ThreeValueHorizontal || style == ThreeValueVertical)
- {
- jassert ((double) valueMin.getValue() <= (double) valueMax.getValue());
-
- newValue = jlimit ((double) valueMin.getValue(),
- (double) valueMax.getValue(),
- newValue);
- }
-
- if (newValue != lastCurrentValue)
- {
- if (valueBox != nullptr)
- valueBox->hideEditor (true);
-
- lastCurrentValue = newValue;
-
- // (need to do this comparison because the Value will use equalsWithSameType to compare
- // the new and old values, so will generate unwanted change events if the type changes)
- if (currentValue != newValue)
- currentValue = newValue;
-
- updateText();
- owner.repaint();
-
- if (popupDisplay != nullptr)
- popupDisplay->updatePosition (owner.getTextFromValue (newValue));
-
- triggerChangeMessage (notification);
- }
- }
-
- void setMinValue (double newValue, const NotificationType notification,
- const bool allowNudgingOfOtherValues)
- {
- // The minimum value only applies to sliders that are in two- or three-value mode.
- jassert (style == TwoValueHorizontal || style == TwoValueVertical
- || style == ThreeValueHorizontal || style == ThreeValueVertical);
-
- newValue = constrainedValue (newValue);
-
- if (style == TwoValueHorizontal || style == TwoValueVertical)
- {
- if (allowNudgingOfOtherValues && newValue > (double) valueMax.getValue())
- setMaxValue (newValue, notification, false);
-
- newValue = jmin ((double) valueMax.getValue(), newValue);
- }
- else
- {
- if (allowNudgingOfOtherValues && newValue > lastCurrentValue)
- setValue (newValue, notification);
-
- newValue = jmin (lastCurrentValue, newValue);
- }
-
- if (lastValueMin != newValue)
- {
- lastValueMin = newValue;
- valueMin = newValue;
- owner.repaint();
-
- if (popupDisplay != nullptr)
- popupDisplay->updatePosition (owner.getTextFromValue (newValue));
-
- triggerChangeMessage (notification);
- }
- }
-
- void setMaxValue (double newValue, const NotificationType notification,
- const bool allowNudgingOfOtherValues)
- {
- // The maximum value only applies to sliders that are in two- or three-value mode.
- jassert (style == TwoValueHorizontal || style == TwoValueVertical
- || style == ThreeValueHorizontal || style == ThreeValueVertical);
-
- newValue = constrainedValue (newValue);
-
- if (style == TwoValueHorizontal || style == TwoValueVertical)
- {
- if (allowNudgingOfOtherValues && newValue < (double) valueMin.getValue())
- setMinValue (newValue, notification, false);
-
- newValue = jmax ((double) valueMin.getValue(), newValue);
- }
- else
- {
- if (allowNudgingOfOtherValues && newValue < lastCurrentValue)
- setValue (newValue, notification);
-
- newValue = jmax (lastCurrentValue, newValue);
- }
-
- if (lastValueMax != newValue)
- {
- lastValueMax = newValue;
- valueMax = newValue;
- owner.repaint();
-
- if (popupDisplay != nullptr)
- popupDisplay->updatePosition (owner.getTextFromValue (valueMax.getValue()));
-
- triggerChangeMessage (notification);
- }
- }
-
- void setMinAndMaxValues (double newMinValue, double newMaxValue, const NotificationType notification)
- {
- // The maximum value only applies to sliders that are in two- or three-value mode.
- jassert (style == TwoValueHorizontal || style == TwoValueVertical
- || style == ThreeValueHorizontal || style == ThreeValueVertical);
-
- if (newMaxValue < newMinValue)
- std::swap (newMaxValue, newMinValue);
-
- newMinValue = constrainedValue (newMinValue);
- newMaxValue = constrainedValue (newMaxValue);
-
- if (lastValueMax != newMaxValue || lastValueMin != newMinValue)
- {
- lastValueMax = newMaxValue;
- lastValueMin = newMinValue;
- valueMin = newMinValue;
- valueMax = newMaxValue;
- owner.repaint();
-
- triggerChangeMessage (notification);
- }
- }
-
- double getMinValue() const
- {
- // The minimum value only applies to sliders that are in two- or three-value mode.
- jassert (style == TwoValueHorizontal || style == TwoValueVertical
- || style == ThreeValueHorizontal || style == ThreeValueVertical);
-
- return valueMin.getValue();
- }
-
- double getMaxValue() const
- {
- // The maximum value only applies to sliders that are in two- or three-value mode.
- jassert (style == TwoValueHorizontal || style == TwoValueVertical
- || style == ThreeValueHorizontal || style == ThreeValueVertical);
-
- return valueMax.getValue();
- }
-
- void triggerChangeMessage (const NotificationType notification)
- {
- if (notification != dontSendNotification)
- {
- owner.valueChanged();
-
- if (notification == sendNotificationSync)
- handleAsyncUpdate();
- else
- triggerAsyncUpdate();
- }
- }
-
- void handleAsyncUpdate() override
- {
- cancelPendingUpdate();
-
- Component::BailOutChecker checker (&owner);
- Slider* slider = &owner; // (must use an intermediate variable here to avoid a VS2005 compiler bug)
- listeners.callChecked (checker, &SliderListener::sliderValueChanged, slider); // (can't use Slider::Listener due to idiotic VC2005 bug)
- }
-
- void sendDragStart()
- {
- owner.startedDragging();
-
- Component::BailOutChecker checker (&owner);
- Slider* slider = &owner; // (must use an intermediate variable here to avoid a VS2005 compiler bug)
- listeners.callChecked (checker, &SliderListener::sliderDragStarted, slider);
- }
-
- void sendDragEnd()
- {
- owner.stoppedDragging();
-
- sliderBeingDragged = -1;
-
- Component::BailOutChecker checker (&owner);
- Slider* slider = &owner; // (must use an intermediate variable here to avoid a VS2005 compiler bug)
- listeners.callChecked (checker, &SliderListener::sliderDragEnded, slider);
- }
-
- struct DragInProgress
- {
- DragInProgress (Pimpl& p) : owner (p) { owner.sendDragStart(); }
- ~DragInProgress() { owner.sendDragEnd(); }
-
- Pimpl& owner;
-
- JUCE_DECLARE_NON_COPYABLE (DragInProgress)
- };
-
- void buttonClicked (Button* button) override
- {
- if (style == IncDecButtons)
- {
- const double delta = (button == incButton) ? interval : -interval;
-
- DragInProgress drag (*this);
- setValue (owner.snapValue (getValue() + delta, notDragging), sendNotificationSync);
- }
- }
-
- void valueChanged (Value& value) override
- {
- if (value.refersToSameSourceAs (currentValue))
- {
- if (style != TwoValueHorizontal && style != TwoValueVertical)
- setValue (currentValue.getValue(), dontSendNotification);
- }
- else if (value.refersToSameSourceAs (valueMin))
- setMinValue (valueMin.getValue(), dontSendNotification, true);
- else if (value.refersToSameSourceAs (valueMax))
- setMaxValue (valueMax.getValue(), dontSendNotification, true);
- }
-
- void labelTextChanged (Label* label) override
- {
- const double newValue = owner.snapValue (owner.getValueFromText (label->getText()), notDragging);
-
- if (newValue != (double) currentValue.getValue())
- {
- DragInProgress drag (*this);
- setValue (newValue, sendNotificationSync);
- }
-
- updateText(); // force a clean-up of the text, needed in case setValue() hasn't done this.
- }
-
- void updateText()
- {
- if (valueBox != nullptr)
- {
- String newValue (owner.getTextFromValue (currentValue.getValue()));
-
- if (newValue != valueBox->getText())
- valueBox->setText (newValue, dontSendNotification);
- }
- }
-
- 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;
- }
-
- float getLinearSliderPos (const double value) const
- {
- double pos;
-
- if (maximum <= minimum)
- pos = 0.5;
- else if (value < minimum)
- pos = 0.0;
- else if (value > maximum)
- pos = 1.0;
- else
- pos = owner.valueToProportionOfLength (value);
-
- if (isVertical() || style == IncDecButtons)
- pos = 1.0 - pos;
-
- jassert (pos >= 0 && pos <= 1.0);
- return (float) (sliderRegionStart + pos * sliderRegionSize);
- }
-
- void setSliderStyle (const SliderStyle newStyle)
- {
- if (style != newStyle)
- {
- style = newStyle;
- owner.repaint();
- owner.lookAndFeelChanged();
- }
- }
-
- void setRotaryParameters (const float startAngleRadians,
- const float endAngleRadians,
- const bool stopAtEnd)
- {
- // make sure the values are sensible..
- jassert (startAngleRadians >= 0 && endAngleRadians >= 0);
- jassert (startAngleRadians < float_Pi * 4.0f && endAngleRadians < float_Pi * 4.0f);
- jassert (startAngleRadians < endAngleRadians);
-
- rotaryStart = startAngleRadians;
- rotaryEnd = endAngleRadians;
- rotaryStop = stopAtEnd;
- }
-
- void setVelocityModeParameters (const double sensitivity, const int threshold,
- const double offset, const bool userCanPressKeyToSwapMode)
- {
- velocityModeSensitivity = sensitivity;
- velocityModeOffset = offset;
- velocityModeThreshold = threshold;
- userKeyOverridesVelocity = userCanPressKeyToSwapMode;
- }
-
- void setSkewFactorFromMidPoint (const double sliderValueToShowAtMidPoint)
- {
- if (maximum > minimum)
- skewFactor = log (0.5) / log ((sliderValueToShowAtMidPoint - minimum)
- / (maximum - minimum));
- }
-
- void setIncDecButtonsMode (const IncDecButtonMode mode)
- {
- if (incDecButtonMode != mode)
- {
- incDecButtonMode = mode;
- owner.lookAndFeelChanged();
- }
- }
-
- void setTextBoxStyle (const TextEntryBoxPosition newPosition,
- const bool isReadOnly,
- const int textEntryBoxWidth,
- const int textEntryBoxHeight)
- {
- if (textBoxPos != newPosition
- || editableText != (! isReadOnly)
- || textBoxWidth != textEntryBoxWidth
- || textBoxHeight != textEntryBoxHeight)
- {
- textBoxPos = newPosition;
- editableText = ! isReadOnly;
- textBoxWidth = textEntryBoxWidth;
- textBoxHeight = textEntryBoxHeight;
-
- owner.repaint();
- owner.lookAndFeelChanged();
- }
- }
-
- void setTextBoxIsEditable (const bool shouldBeEditable)
- {
- editableText = shouldBeEditable;
-
- if (valueBox != nullptr)
- valueBox->setEditable (shouldBeEditable && owner.isEnabled());
- }
-
- void showTextBox()
- {
- jassert (editableText); // this should probably be avoided in read-only sliders.
-
- if (valueBox != nullptr)
- valueBox->showEditor();
- }
-
- void hideTextBox (const bool discardCurrentEditorContents)
- {
- if (valueBox != nullptr)
- {
- valueBox->hideEditor (discardCurrentEditorContents);
-
- if (discardCurrentEditorContents)
- updateText();
- }
- }
-
- void setTextValueSuffix (const String& suffix)
- {
- if (textSuffix != suffix)
- {
- textSuffix = suffix;
- updateText();
- }
- }
-
- void lookAndFeelChanged (LookAndFeel& lf)
- {
- if (textBoxPos != NoTextBox)
- {
- const String previousTextBoxContent (valueBox != nullptr ? valueBox->getText()
- : owner.getTextFromValue (currentValue.getValue()));
-
- valueBox = nullptr;
- owner.addAndMakeVisible (valueBox = lf.createSliderTextBox (owner));
-
- valueBox->setWantsKeyboardFocus (false);
- valueBox->setText (previousTextBoxContent, dontSendNotification);
- valueBox->setTooltip (owner.getTooltip());
-
- if (valueBox->isEditable() != editableText) // (avoid overriding the single/double click flags unless we have to)
- valueBox->setEditable (editableText && owner.isEnabled());
-
- valueBox->addListener (this);
-
- if (style == LinearBar || style == LinearBarVertical)
- {
- valueBox->addMouseListener (&owner, false);
- valueBox->setMouseCursor (MouseCursor::ParentCursor);
- }
- }
- else
- {
- valueBox = nullptr;
- }
-
- if (style == IncDecButtons)
- {
- owner.addAndMakeVisible (incButton = lf.createSliderButton (owner, true));
- incButton->addListener (this);
-
- owner.addAndMakeVisible (decButton = lf.createSliderButton (owner, false));
- decButton->addListener (this);
-
- if (incDecButtonMode != incDecButtonsNotDraggable)
- {
- incButton->addMouseListener (&owner, false);
- decButton->addMouseListener (&owner, false);
- }
- else
- {
- incButton->setRepeatSpeed (300, 100, 20);
- decButton->setRepeatSpeed (300, 100, 20);
- }
-
- const String tooltip (owner.getTooltip());
- incButton->setTooltip (tooltip);
- decButton->setTooltip (tooltip);
- }
- else
- {
- incButton = nullptr;
- decButton = nullptr;
- }
-
- owner.setComponentEffect (lf.getSliderEffect (owner));
-
- owner.resized();
- owner.repaint();
- }
-
- void showPopupMenu()
- {
- PopupMenu m;
- m.setLookAndFeel (&owner.getLookAndFeel());
- m.addItem (1, TRANS ("Velocity-sensitive mode"), true, isVelocityBased);
- m.addSeparator();
-
- if (isRotary())
- {
- PopupMenu rotaryMenu;
- rotaryMenu.addItem (2, TRANS ("Use circular dragging"), true, style == Rotary);
- rotaryMenu.addItem (3, TRANS ("Use left-right dragging"), true, style == RotaryHorizontalDrag);
- rotaryMenu.addItem (4, TRANS ("Use up-down dragging"), true, style == RotaryVerticalDrag);
- rotaryMenu.addItem (5, TRANS ("Use left-right/up-down dragging"), true, style == RotaryHorizontalVerticalDrag);
-
- m.addSubMenu (TRANS ("Rotary mode"), rotaryMenu);
- }
-
- m.showMenuAsync (PopupMenu::Options(),
- ModalCallbackFunction::forComponent (sliderMenuCallback, &owner));
- }
-
- static void sliderMenuCallback (const int result, Slider* slider)
- {
- if (slider != nullptr)
- {
- switch (result)
- {
- case 1: slider->setVelocityBasedMode (! slider->getVelocityBasedMode()); break;
- case 2: slider->setSliderStyle (Rotary); break;
- case 3: slider->setSliderStyle (RotaryHorizontalDrag); break;
- case 4: slider->setSliderStyle (RotaryVerticalDrag); break;
- case 5: slider->setSliderStyle (RotaryHorizontalVerticalDrag); break;
- default: break;
- }
- }
- }
-
- int getThumbIndexAt (const MouseEvent& e)
- {
- const bool isTwoValue = (style == TwoValueHorizontal || style == TwoValueVertical);
- const bool isThreeValue = (style == ThreeValueHorizontal || style == ThreeValueVertical);
-
- if (isTwoValue || isThreeValue)
- {
- const float mousePos = isVertical() ? e.position.y : e.position.x;
-
- const float normalPosDistance = std::abs (getLinearSliderPos (currentValue.getValue()) - mousePos);
- const float minPosDistance = std::abs (getLinearSliderPos (valueMin.getValue()) - 0.1f - mousePos);
- const float maxPosDistance = std::abs (getLinearSliderPos (valueMax.getValue()) + 0.1f - mousePos);
-
- if (isTwoValue)
- return maxPosDistance <= minPosDistance ? 2 : 1;
-
- if (normalPosDistance >= minPosDistance && maxPosDistance >= minPosDistance)
- return 1;
-
- if (normalPosDistance >= maxPosDistance)
- return 2;
- }
-
- return 0;
- }
-
- //==============================================================================
- void handleRotaryDrag (const MouseEvent& e)
- {
- const float dx = e.position.x - sliderRect.getCentreX();
- const float dy = e.position.y - sliderRect.getCentreY();
-
- if (dx * dx + dy * dy > 25.0f)
- {
- double angle = std::atan2 ((double) dx, (double) -dy);
- while (angle < 0.0)
- angle += double_Pi * 2.0;
-
- if (rotaryStop && ! e.mouseWasClicked())
- {
- if (std::abs (angle - lastAngle) > double_Pi)
- {
- if (angle >= lastAngle)
- angle -= double_Pi * 2.0;
- else
- angle += double_Pi * 2.0;
- }
-
- if (angle >= lastAngle)
- angle = jmin (angle, (double) jmax (rotaryStart, rotaryEnd));
- else
- angle = jmax (angle, (double) jmin (rotaryStart, rotaryEnd));
- }
- else
- {
- while (angle < rotaryStart)
- angle += double_Pi * 2.0;
-
- if (angle > rotaryEnd)
- {
- if (smallestAngleBetween (angle, rotaryStart)
- <= smallestAngleBetween (angle, rotaryEnd))
- angle = rotaryStart;
- else
- angle = rotaryEnd;
- }
- }
-
- const double proportion = (angle - rotaryStart) / (rotaryEnd - rotaryStart);
- valueWhenLastDragged = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, proportion));
- lastAngle = angle;
- }
- }
-
- void handleAbsoluteDrag (const MouseEvent& e)
- {
- const float mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.position.x : e.position.y;
- double newPos = (mousePos - sliderRegionStart) / (double) sliderRegionSize;
-
- if (style == RotaryHorizontalDrag
- || style == RotaryVerticalDrag
- || style == IncDecButtons
- || ((style == LinearHorizontal || style == LinearVertical || style == LinearBar || style == LinearBarVertical)
- && ! snapsToMousePos))
- {
- const float mouseDiff = (style == RotaryHorizontalDrag
- || style == LinearHorizontal
- || style == LinearBar
- || (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
- ? e.position.x - mouseDragStartPos.x
- : mouseDragStartPos.y - e.position.y;
-
- newPos = owner.valueToProportionOfLength (valueOnMouseDown)
- + mouseDiff * (1.0 / pixelsForFullDragExtent);
-
- if (style == IncDecButtons)
- {
- incButton->setState (mouseDiff < 0 ? Button::buttonNormal : Button::buttonDown);
- decButton->setState (mouseDiff > 0 ? Button::buttonNormal : Button::buttonDown);
- }
- }
- else if (style == RotaryHorizontalVerticalDrag)
- {
- const float mouseDiff = (e.position.x - mouseDragStartPos.x)
- + (mouseDragStartPos.y - e.position.y);
-
- newPos = owner.valueToProportionOfLength (valueOnMouseDown)
- + mouseDiff * (1.0 / pixelsForFullDragExtent);
- }
- else
- {
- if (isVertical())
- newPos = 1.0 - newPos;
- }
-
- valueWhenLastDragged = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, newPos));
- }
-
- void handleVelocityDrag (const MouseEvent& e)
- {
- const float mouseDiff = style == RotaryHorizontalVerticalDrag
- ? (e.position.x - mousePosWhenLastDragged.x) + (mousePosWhenLastDragged.y - e.position.y)
- : (isHorizontal()
- || style == RotaryHorizontalDrag
- || (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
- ? e.position.x - mousePosWhenLastDragged.x
- : e.position.y - mousePosWhenLastDragged.y;
-
- const double maxSpeed = jmax (200, sliderRegionSize);
- double speed = jlimit (0.0, maxSpeed, (double) std::abs (mouseDiff));
-
- if (speed != 0)
- {
- speed = 0.2 * velocityModeSensitivity
- * (1.0 + std::sin (double_Pi * (1.5 + jmin (0.5, velocityModeOffset
- + jmax (0.0, (double) (speed - velocityModeThreshold))
- / maxSpeed))));
-
- if (mouseDiff < 0)
- speed = -speed;
-
- if (isVertical() || style == RotaryVerticalDrag
- || (style == IncDecButtons && ! incDecDragDirectionIsHorizontal()))
- speed = -speed;
-
- const double currentPos = owner.valueToProportionOfLength (valueWhenLastDragged);
-
- valueWhenLastDragged = owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + speed));
-
- e.source.enableUnboundedMouseMovement (true, false);
- }
- }
-
- void mouseDown (const MouseEvent& e)
- {
- incDecDragged = false;
- useDragEvents = false;
- mouseDragStartPos = mousePosWhenLastDragged = e.position;
- currentDrag = nullptr;
-
- if (owner.isEnabled())
- {
- if (e.mods.isPopupMenu() && menuEnabled)
- {
- showPopupMenu();
- }
- else if (canDoubleClickToValue() && e.mods.isAltDown())
- {
- mouseDoubleClick();
- }
- else if (maximum > minimum)
- {
- useDragEvents = true;
-
- if (valueBox != nullptr)
- valueBox->hideEditor (true);
-
- sliderBeingDragged = getThumbIndexAt (e);
-
- minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue();
-
- lastAngle = rotaryStart + (rotaryEnd - rotaryStart)
- * owner.valueToProportionOfLength (currentValue.getValue());
-
- valueWhenLastDragged = (sliderBeingDragged == 2 ? valueMax
- : (sliderBeingDragged == 1 ? valueMin
- : currentValue)).getValue();
- valueOnMouseDown = valueWhenLastDragged;
-
- if (popupDisplayEnabled)
- {
- PopupDisplayComponent* const popup = new PopupDisplayComponent (owner);
- popupDisplay = popup;
-
- if (parentForPopupDisplay != nullptr)
- parentForPopupDisplay->addChildComponent (popup);
- else
- popup->addToDesktop (0);
-
- popup->setVisible (true);
- }
-
- currentDrag = new DragInProgress (*this);
- mouseDrag (e);
- }
- }
- }
-
- void mouseDrag (const MouseEvent& e)
- {
- if (useDragEvents && maximum > minimum
- && ! ((style == LinearBar || style == LinearBarVertical)
- && e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable()))
- {
- DragMode dragMode = notDragging;
-
- if (style == Rotary)
- {
- handleRotaryDrag (e);
- }
- else
- {
- if (style == IncDecButtons && ! incDecDragged)
- {
- if (e.getDistanceFromDragStart() < 10 || e.mouseWasClicked())
- return;
-
- incDecDragged = true;
- mouseDragStartPos = e.position;
- }
-
- if (isAbsoluteDragMode (e.mods) || (maximum - minimum) / sliderRegionSize < interval)
- {
- dragMode = absoluteDrag;
- handleAbsoluteDrag (e);
- }
- else
- {
- dragMode = velocityDrag;
- handleVelocityDrag (e);
- }
- }
-
- valueWhenLastDragged = jlimit (minimum, maximum, valueWhenLastDragged);
-
- if (sliderBeingDragged == 0)
- {
- setValue (owner.snapValue (valueWhenLastDragged, dragMode),
- sendChangeOnlyOnRelease ? dontSendNotification : sendNotificationSync);
- }
- else if (sliderBeingDragged == 1)
- {
- setMinValue (owner.snapValue (valueWhenLastDragged, dragMode),
- sendChangeOnlyOnRelease ? dontSendNotification : sendNotificationAsync, true);
-
- if (e.mods.isShiftDown())
- setMaxValue (getMinValue() + minMaxDiff, dontSendNotification, true);
- else
- minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue();
- }
- else if (sliderBeingDragged == 2)
- {
- setMaxValue (owner.snapValue (valueWhenLastDragged, dragMode),
- sendChangeOnlyOnRelease ? dontSendNotification : sendNotificationAsync, true);
-
- if (e.mods.isShiftDown())
- setMinValue (getMaxValue() - minMaxDiff, dontSendNotification, true);
- else
- minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue();
- }
-
- mousePosWhenLastDragged = e.position;
- }
- }
-
- void mouseUp()
- {
- if (owner.isEnabled()
- && useDragEvents
- && (maximum > minimum)
- && (style != IncDecButtons || incDecDragged))
- {
- restoreMouseIfHidden();
-
- if (sendChangeOnlyOnRelease && valueOnMouseDown != (double) currentValue.getValue())
- triggerChangeMessage (sendNotificationAsync);
-
- currentDrag = nullptr;
- popupDisplay = nullptr;
-
- if (style == IncDecButtons)
- {
- incButton->setState (Button::buttonNormal);
- decButton->setState (Button::buttonNormal);
- }
- }
- else if (popupDisplay != nullptr)
- {
- popupDisplay->startTimer (2000);
- }
-
- currentDrag = nullptr;
- }
-
- bool canDoubleClickToValue() const
- {
- return doubleClickToValue
- && style != IncDecButtons
- && minimum <= doubleClickReturnValue
- && maximum >= doubleClickReturnValue;
- }
-
- void mouseDoubleClick()
- {
- if (canDoubleClickToValue())
- {
- DragInProgress drag (*this);
- setValue (doubleClickReturnValue, sendNotificationSync);
- }
- }
-
- double getMouseWheelDelta (double value, double wheelAmount)
- {
- if (style == IncDecButtons)
- return interval * wheelAmount;
-
- const double proportionDelta = wheelAmount * 0.15f;
- const double currentPos = owner.valueToProportionOfLength (value);
- return owner.proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + proportionDelta)) - value;
- }
-
- 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;
-
- if (maximum > minimum && ! e.mods.isAnyMouseButtonDown())
- {
- if (valueBox != nullptr)
- valueBox->hideEditor (false);
-
- const double value = (double) currentValue.getValue();
- const double delta = getMouseWheelDelta (value, (std::abs (wheel.deltaX) > std::abs (wheel.deltaY)
- ? -wheel.deltaX : wheel.deltaY)
- * (wheel.isReversed ? -1.0f : 1.0f));
- if (delta != 0)
- {
- const double newValue = value + jmax (interval, std::abs (delta)) * (delta < 0 ? -1.0 : 1.0);
-
- DragInProgress drag (*this);
- setValue (owner.snapValue (newValue, notDragging), sendNotificationSync);
- }
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- void modifierKeysChanged (const ModifierKeys& modifiers)
- {
- if (style != IncDecButtons && style != Rotary && isAbsoluteDragMode (modifiers))
- restoreMouseIfHidden();
- }
-
- bool isAbsoluteDragMode (ModifierKeys mods) const
- {
- return isVelocityBased == (userKeyOverridesVelocity
- && mods.testFlags (ModifierKeys::ctrlAltCommandModifiers));
- }
-
- void restoreMouseIfHidden()
- {
- const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources();
-
- for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi)
- {
- if (mi->isUnboundedMouseMovementEnabled())
- {
- mi->enableUnboundedMouseMovement (false);
-
- const double pos = sliderBeingDragged == 2 ? getMaxValue()
- : (sliderBeingDragged == 1 ? getMinValue()
- : (double) currentValue.getValue());
- Point<float> mousePos;
-
- if (isRotary())
- {
- mousePos = mi->getLastMouseDownPosition();
-
- const float delta = (float) (pixelsForFullDragExtent * (owner.valueToProportionOfLength (valueOnMouseDown)
- - owner.valueToProportionOfLength (pos)));
-
- if (style == RotaryHorizontalDrag) mousePos += Point<float> (-delta, 0.0f);
- else if (style == RotaryVerticalDrag) mousePos += Point<float> (0.0f, delta);
- else mousePos += Point<float> (delta / -2.0f, delta / 2.0f);
-
- mousePos = owner.getScreenBounds().reduced (4).toFloat().getConstrainedPoint (mousePos);
- mouseDragStartPos = mousePosWhenLastDragged = owner.getLocalPoint (nullptr, mousePos);
- valueOnMouseDown = valueWhenLastDragged;
- }
- else
- {
- const float pixelPos = (float) getLinearSliderPos (pos);
-
- mousePos = owner.localPointToGlobal (Point<float> (isHorizontal() ? pixelPos : (owner.getWidth() / 2.0f),
- isVertical() ? pixelPos : (owner.getHeight() / 2.0f)));
- }
-
- mi->setScreenPosition (mousePos);
- }
- }
- }
-
- //==============================================================================
- void paint (Graphics& g, LookAndFeel& lf)
- {
- if (style != IncDecButtons)
- {
- if (isRotary())
- {
- const float sliderPos = (float) owner.valueToProportionOfLength (lastCurrentValue);
- jassert (sliderPos >= 0 && sliderPos <= 1.0f);
-
- lf.drawRotarySlider (g,
- sliderRect.getX(), sliderRect.getY(),
- sliderRect.getWidth(), sliderRect.getHeight(),
- sliderPos, rotaryStart, rotaryEnd, owner);
- }
- else
- {
- lf.drawLinearSlider (g,
- sliderRect.getX(), sliderRect.getY(),
- sliderRect.getWidth(), sliderRect.getHeight(),
- getLinearSliderPos (lastCurrentValue),
- getLinearSliderPos (lastValueMin),
- getLinearSliderPos (lastValueMax),
- style, owner);
- }
-
- if ((style == LinearBar || style == LinearBarVertical) && valueBox == nullptr)
- {
- g.setColour (owner.findColour (Slider::textBoxOutlineColourId));
- g.drawRect (0, 0, owner.getWidth(), owner.getHeight(), 1);
- }
- }
- }
-
- void resized (const Rectangle<int>& localBounds, LookAndFeel& lf)
- {
- int minXSpace = 0;
- int minYSpace = 0;
-
- if (textBoxPos == TextBoxLeft || textBoxPos == TextBoxRight)
- minXSpace = 30;
- else
- minYSpace = 15;
-
- const int tbw = jmax (0, jmin (textBoxWidth, localBounds.getWidth() - minXSpace));
- const int tbh = jmax (0, jmin (textBoxHeight, localBounds.getHeight() - minYSpace));
-
- if (style == LinearBar || style == LinearBarVertical)
- {
- if (valueBox != nullptr)
- valueBox->setBounds (localBounds);
- }
- else
- {
- if (textBoxPos == NoTextBox)
- {
- sliderRect = localBounds;
- }
- else if (textBoxPos == TextBoxLeft)
- {
- valueBox->setBounds (0, (localBounds.getHeight() - tbh) / 2, tbw, tbh);
- sliderRect.setBounds (tbw, 0, localBounds.getWidth() - tbw, localBounds.getHeight());
- }
- else if (textBoxPos == TextBoxRight)
- {
- valueBox->setBounds (localBounds.getWidth() - tbw, (localBounds.getHeight() - tbh) / 2, tbw, tbh);
- sliderRect.setBounds (0, 0, localBounds.getWidth() - tbw, localBounds.getHeight());
- }
- else if (textBoxPos == TextBoxAbove)
- {
- valueBox->setBounds ((localBounds.getWidth() - tbw) / 2, 0, tbw, tbh);
- sliderRect.setBounds (0, tbh, localBounds.getWidth(), localBounds.getHeight() - tbh);
- }
- else if (textBoxPos == TextBoxBelow)
- {
- valueBox->setBounds ((localBounds.getWidth() - tbw) / 2, localBounds.getHeight() - tbh, tbw, tbh);
- sliderRect.setBounds (0, 0, localBounds.getWidth(), localBounds.getHeight() - tbh);
- }
- }
-
- const int indent = lf.getSliderThumbRadius (owner);
-
- if (style == LinearBar)
- {
- const int barIndent = 1;
- sliderRegionStart = barIndent;
- sliderRegionSize = localBounds.getWidth() - barIndent * 2;
-
- sliderRect.setBounds (sliderRegionStart, barIndent,
- sliderRegionSize, localBounds.getHeight() - barIndent * 2);
- }
- else if (style == LinearBarVertical)
- {
- const int barIndent = 1;
- sliderRegionStart = barIndent;
- sliderRegionSize = localBounds.getHeight() - barIndent * 2;
-
- sliderRect.setBounds (barIndent, sliderRegionStart,
- localBounds.getWidth() - barIndent * 2, sliderRegionSize);
- }
- else if (isHorizontal())
- {
- sliderRegionStart = sliderRect.getX() + indent;
- sliderRegionSize = jmax (1, sliderRect.getWidth() - indent * 2);
-
- sliderRect.setBounds (sliderRegionStart, sliderRect.getY(),
- sliderRegionSize, sliderRect.getHeight());
- }
- else if (isVertical())
- {
- sliderRegionStart = sliderRect.getY() + indent;
- sliderRegionSize = jmax (1, sliderRect.getHeight() - indent * 2);
-
- sliderRect.setBounds (sliderRect.getX(), sliderRegionStart,
- sliderRect.getWidth(), sliderRegionSize);
- }
- else
- {
- sliderRegionStart = 0;
- sliderRegionSize = 100;
- }
-
- if (style == IncDecButtons)
- resizeIncDecButtons();
- }
-
- void resizeIncDecButtons()
- {
- Rectangle<int> buttonRect (sliderRect);
-
- if (textBoxPos == TextBoxLeft || textBoxPos == TextBoxRight)
- buttonRect.expand (-2, 0);
- else
- buttonRect.expand (0, -2);
-
- incDecButtonsSideBySide = buttonRect.getWidth() > buttonRect.getHeight();
-
- if (incDecButtonsSideBySide)
- {
- decButton->setBounds (buttonRect.removeFromLeft (buttonRect.getWidth() / 2));
- decButton->setConnectedEdges (Button::ConnectedOnRight);
- incButton->setConnectedEdges (Button::ConnectedOnLeft);
- }
- else
- {
- decButton->setBounds (buttonRect.removeFromBottom (buttonRect.getHeight() / 2));
- decButton->setConnectedEdges (Button::ConnectedOnTop);
- incButton->setConnectedEdges (Button::ConnectedOnBottom);
- }
-
- incButton->setBounds (buttonRect);
- }
-
- //==============================================================================
- Slider& owner;
- SliderStyle style;
-
- ListenerList <SliderListener> listeners;
- Value currentValue, valueMin, valueMax;
- double lastCurrentValue, lastValueMin, lastValueMax;
- double minimum, maximum, interval, doubleClickReturnValue;
- double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle;
- double velocityModeSensitivity, velocityModeOffset, minMaxDiff;
- int velocityModeThreshold;
- float rotaryStart, rotaryEnd;
- Point<float> mouseDragStartPos, mousePosWhenLastDragged;
- int sliderRegionStart, sliderRegionSize;
- int sliderBeingDragged;
- int pixelsForFullDragExtent;
- Time lastMouseWheelTime;
- Rectangle<int> sliderRect;
- ScopedPointer<DragInProgress> currentDrag;
-
- TextEntryBoxPosition textBoxPos;
- String textSuffix;
- int numDecimalPlaces;
- int textBoxWidth, textBoxHeight;
- IncDecButtonMode incDecButtonMode;
-
- bool editableText;
- bool doubleClickToValue;
- bool isVelocityBased;
- bool userKeyOverridesVelocity;
- bool rotaryStop;
- bool incDecButtonsSideBySide;
- bool sendChangeOnlyOnRelease;
- bool popupDisplayEnabled;
- bool menuEnabled;
- bool useDragEvents;
- bool incDecDragged;
- bool scrollWheelEnabled;
- bool snapsToMousePos;
-
- ScopedPointer<Label> valueBox;
- ScopedPointer<Button> incButton, decButton;
-
- //==============================================================================
- class PopupDisplayComponent : public BubbleComponent,
- public Timer
- {
- public:
- PopupDisplayComponent (Slider& s)
- : owner (s),
- font (s.getLookAndFeel().getSliderPopupFont (s))
- {
- setAlwaysOnTop (true);
- setAllowedPlacement (owner.getLookAndFeel().getSliderPopupPlacement (s));
- setLookAndFeel (&s.getLookAndFeel());
- }
-
- void paintContent (Graphics& g, int w, int h)
- {
- g.setFont (font);
- g.setColour (owner.findColour (TooltipWindow::textColourId, true));
- g.drawFittedText (text, Rectangle<int> (w, h), Justification::centred, 1);
- }
-
- void getContentSize (int& w, int& h)
- {
- w = font.getStringWidth (text) + 18;
- h = (int) (font.getHeight() * 1.6f);
- }
-
- void updatePosition (const String& newText)
- {
- text = newText;
- BubbleComponent::setPosition (&owner);
- repaint();
- }
-
- void timerCallback() override
- {
- owner.pimpl->popupDisplay = nullptr;
- }
-
- private:
- Slider& owner;
- Font font;
- String text;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PopupDisplayComponent)
- };
-
- ScopedPointer<PopupDisplayComponent> popupDisplay;
- Component* parentForPopupDisplay;
-
- //==============================================================================
- static double smallestAngleBetween (const double a1, const double a2) noexcept
- {
- return jmin (std::abs (a1 - a2),
- std::abs (a1 + double_Pi * 2.0 - a2),
- std::abs (a2 + double_Pi * 2.0 - a1));
- }
- };
-
-
- //==============================================================================
- Slider::Slider()
- {
- init (LinearHorizontal, TextBoxLeft);
- }
-
- Slider::Slider (const String& name) : Component (name)
- {
- init (LinearHorizontal, TextBoxLeft);
- }
-
- Slider::Slider (SliderStyle style, TextEntryBoxPosition textBoxPos)
- {
- init (style, textBoxPos);
- }
-
- void Slider::init (SliderStyle style, TextEntryBoxPosition textBoxPos)
- {
- setWantsKeyboardFocus (false);
- setRepaintsOnMouseActivity (true);
-
- pimpl = new Pimpl (*this, style, textBoxPos);
-
- Slider::lookAndFeelChanged();
- updateText();
-
- pimpl->registerListeners();
- }
-
- Slider::~Slider() {}
-
- //==============================================================================
- void Slider::addListener (SliderListener* const listener) { pimpl->listeners.add (listener); }
- void Slider::removeListener (SliderListener* const listener) { pimpl->listeners.remove (listener); }
-
- //==============================================================================
- Slider::SliderStyle Slider::getSliderStyle() const noexcept { return pimpl->style; }
- void Slider::setSliderStyle (const SliderStyle newStyle) { pimpl->setSliderStyle (newStyle); }
-
- void Slider::setRotaryParameters (const float startAngleRadians, const float endAngleRadians, const bool stopAtEnd)
- {
- pimpl->setRotaryParameters (startAngleRadians, endAngleRadians, stopAtEnd);
- }
-
- void Slider::setVelocityBasedMode (bool vb) { pimpl->isVelocityBased = vb; }
- bool Slider::getVelocityBasedMode() const noexcept { return pimpl->isVelocityBased; }
- bool Slider::getVelocityModeIsSwappable() const noexcept { return pimpl->userKeyOverridesVelocity; }
- int Slider::getVelocityThreshold() const noexcept { return pimpl->velocityModeThreshold; }
- double Slider::getVelocitySensitivity() const noexcept { return pimpl->velocityModeSensitivity; }
- double Slider::getVelocityOffset() const noexcept { return pimpl->velocityModeOffset; }
-
- void Slider::setVelocityModeParameters (const double sensitivity, const int threshold,
- const double offset, const bool userCanPressKeyToSwapMode)
- {
- jassert (threshold >= 0);
- jassert (sensitivity > 0);
- jassert (offset >= 0);
-
- pimpl->setVelocityModeParameters (sensitivity, threshold, offset, userCanPressKeyToSwapMode);
- }
-
- double Slider::getSkewFactor() const noexcept { return pimpl->skewFactor; }
- void Slider::setSkewFactor (const double factor) { pimpl->skewFactor = factor; }
-
- void Slider::setSkewFactorFromMidPoint (const double sliderValueToShowAtMidPoint)
- {
- pimpl->setSkewFactorFromMidPoint (sliderValueToShowAtMidPoint);
- }
-
- int Slider::getMouseDragSensitivity() const noexcept { return pimpl->pixelsForFullDragExtent; }
-
- void Slider::setMouseDragSensitivity (const int distanceForFullScaleDrag)
- {
- jassert (distanceForFullScaleDrag > 0);
-
- pimpl->pixelsForFullDragExtent = distanceForFullScaleDrag;
- }
-
- void Slider::setIncDecButtonsMode (const IncDecButtonMode mode) { pimpl->setIncDecButtonsMode (mode); }
-
- Slider::TextEntryBoxPosition Slider::getTextBoxPosition() const noexcept { return pimpl->textBoxPos; }
- int Slider::getTextBoxWidth() const noexcept { return pimpl->textBoxWidth; }
- int Slider::getTextBoxHeight() const noexcept { return pimpl->textBoxHeight; }
-
- void Slider::setTextBoxStyle (const TextEntryBoxPosition newPosition, const bool isReadOnly,
- const int textEntryBoxWidth, const int textEntryBoxHeight)
- {
- pimpl->setTextBoxStyle (newPosition, isReadOnly, textEntryBoxWidth, textEntryBoxHeight);
- }
-
- bool Slider::isTextBoxEditable() const noexcept { return pimpl->editableText; }
- void Slider::setTextBoxIsEditable (const bool shouldBeEditable) { pimpl->setTextBoxIsEditable (shouldBeEditable); }
- void Slider::showTextBox() { pimpl->showTextBox(); }
- void Slider::hideTextBox (const bool discardCurrentEditorContents) { pimpl->hideTextBox (discardCurrentEditorContents); }
-
- void Slider::setChangeNotificationOnlyOnRelease (bool onlyNotifyOnRelease)
- {
- pimpl->sendChangeOnlyOnRelease = onlyNotifyOnRelease;
- }
-
- bool Slider::getSliderSnapsToMousePosition() const noexcept { return pimpl->snapsToMousePos; }
- void Slider::setSliderSnapsToMousePosition (const bool shouldSnapToMouse) { pimpl->snapsToMousePos = shouldSnapToMouse; }
-
- void Slider::setPopupDisplayEnabled (const bool enabled, Component* const parentComponentToUse)
- {
- pimpl->popupDisplayEnabled = enabled;
- pimpl->parentForPopupDisplay = parentComponentToUse;
- }
-
- Component* Slider::getCurrentPopupDisplay() const noexcept { return pimpl->popupDisplay.get(); }
-
- //==============================================================================
- void Slider::colourChanged() { lookAndFeelChanged(); }
- void Slider::lookAndFeelChanged() { pimpl->lookAndFeelChanged (getLookAndFeel()); }
- void Slider::enablementChanged() { repaint(); }
-
- //==============================================================================
- double Slider::getMaximum() const noexcept { return pimpl->maximum; }
- double Slider::getMinimum() const noexcept { return pimpl->minimum; }
- double Slider::getInterval() const noexcept { return pimpl->interval; }
-
- void Slider::setRange (double newMin, double newMax, double newInt)
- {
- pimpl->setRange (newMin, newMax, newInt);
- }
-
- Value& Slider::getValueObject() noexcept { return pimpl->currentValue; }
- Value& Slider::getMinValueObject() noexcept { return pimpl->valueMin; }
- Value& Slider::getMaxValueObject() noexcept { return pimpl->valueMax; }
-
- double Slider::getValue() const { return pimpl->getValue(); }
-
- void Slider::setValue (double newValue, const NotificationType notification)
- {
- pimpl->setValue (newValue, notification);
- }
-
- double Slider::getMinValue() const { return pimpl->getMinValue(); }
- double Slider::getMaxValue() const { return pimpl->getMaxValue(); }
-
- void Slider::setMinValue (double newValue, const NotificationType notification, bool allowNudgingOfOtherValues)
- {
- pimpl->setMinValue (newValue, notification, allowNudgingOfOtherValues);
- }
-
- void Slider::setMaxValue (double newValue, const NotificationType notification, bool allowNudgingOfOtherValues)
- {
- pimpl->setMaxValue (newValue, notification, allowNudgingOfOtherValues);
- }
-
- void Slider::setMinAndMaxValues (double newMinValue, double newMaxValue, const NotificationType notification)
- {
- pimpl->setMinAndMaxValues (newMinValue, newMaxValue, notification);
- }
-
- void Slider::setDoubleClickReturnValue (bool isDoubleClickEnabled, double valueToSetOnDoubleClick)
- {
- pimpl->doubleClickToValue = isDoubleClickEnabled;
- pimpl->doubleClickReturnValue = valueToSetOnDoubleClick;
- }
-
- double Slider::getDoubleClickReturnValue (bool& isEnabledResult) const
- {
- isEnabledResult = pimpl->doubleClickToValue;
- return pimpl->doubleClickReturnValue;
- }
-
- void Slider::updateText()
- {
- pimpl->updateText();
- }
-
- void Slider::setTextValueSuffix (const String& suffix)
- {
- pimpl->setTextValueSuffix (suffix);
- }
-
- String Slider::getTextValueSuffix() const
- {
- return pimpl->textSuffix;
- }
-
- String Slider::getTextFromValue (double v)
- {
- if (getNumDecimalPlacesToDisplay() > 0)
- return String (v, getNumDecimalPlacesToDisplay()) + getTextValueSuffix();
-
- return String (roundToInt (v)) + getTextValueSuffix();
- }
-
- double Slider::getValueFromText (const String& text)
- {
- String t (text.trimStart());
-
- if (t.endsWith (getTextValueSuffix()))
- t = t.substring (0, t.length() - getTextValueSuffix().length());
-
- while (t.startsWithChar ('+'))
- t = t.substring (1).trimStart();
-
- return t.initialSectionContainingOnly ("0123456789.,-")
- .getDoubleValue();
- }
-
- double Slider::proportionOfLengthToValue (double proportion)
- {
- const double skew = getSkewFactor();
-
- if (skew != 1.0 && proportion > 0.0)
- proportion = exp (log (proportion) / skew);
-
- return getMinimum() + (getMaximum() - getMinimum()) * proportion;
- }
-
- double Slider::valueToProportionOfLength (double value)
- {
- const double n = (value - getMinimum()) / (getMaximum() - getMinimum());
- const double skew = getSkewFactor();
-
- return skew == 1.0 ? n : pow (n, skew);
- }
-
- double Slider::snapValue (double attemptedValue, DragMode)
- {
- return attemptedValue;
- }
-
- int Slider::getNumDecimalPlacesToDisplay() const noexcept { return pimpl->numDecimalPlaces; }
-
- //==============================================================================
- int Slider::getThumbBeingDragged() const noexcept { return pimpl->sliderBeingDragged; }
-
- void Slider::startedDragging() {}
- void Slider::stoppedDragging() {}
- void Slider::valueChanged() {}
-
- //==============================================================================
- void Slider::setPopupMenuEnabled (const bool menuEnabled) { pimpl->menuEnabled = menuEnabled; }
- void Slider::setScrollWheelEnabled (const bool enabled) { pimpl->scrollWheelEnabled = enabled; }
-
- bool Slider::isHorizontal() const noexcept { return pimpl->isHorizontal(); }
- bool Slider::isVertical() const noexcept { return pimpl->isVertical(); }
-
- float Slider::getPositionOfValue (const double value) { return pimpl->getPositionOfValue (value); }
-
- //==============================================================================
- void Slider::paint (Graphics& g) { pimpl->paint (g, getLookAndFeel()); }
- void Slider::resized() { pimpl->resized (getLocalBounds(), getLookAndFeel()); }
-
- void Slider::focusOfChildComponentChanged (FocusChangeType) { repaint(); }
-
- void Slider::mouseDown (const MouseEvent& e) { pimpl->mouseDown (e); }
- void Slider::mouseUp (const MouseEvent&) { pimpl->mouseUp(); }
-
- void Slider::modifierKeysChanged (const ModifierKeys& modifiers)
- {
- if (isEnabled())
- pimpl->modifierKeysChanged (modifiers);
- }
-
- void Slider::mouseDrag (const MouseEvent& e)
- {
- if (isEnabled())
- pimpl->mouseDrag (e);
- }
-
- void Slider::mouseDoubleClick (const MouseEvent&)
- {
- if (isEnabled())
- pimpl->mouseDoubleClick();
- }
-
- void Slider::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel)
- {
- if (! (isEnabled() && pimpl->mouseWheelMove (e, wheel)))
- Component::mouseWheelMove (e, wheel);
- }
|