< Summary

Class:UIComponents.Scripts.Components.RangeSlider.RangeSlider
Assembly:UIComponents
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/UIComponents/Scripts/Components/RangeSlider/RangeSlider.cs
Covered lines:45
Uncovered lines:174
Coverable lines:219
Total lines:602
Line coverage:20.5% (45 of 219)
Covered branches:0
Total branches:0
Covered methods:20
Total methods:51
Method coverage:39.2% (20 of 51)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
RangeSlider()0%110100%
SetValueWithoutNotify(...)0%2100%
OnValidate()0%6.815058.33%
Rebuild(...)0%6200%
LayoutComplete()0%2100%
GraphicUpdateComplete()0%2100%
SetClass[T](...)0%30500%
SetStruct[T](...)0%2.52050%
OnEnable()0%2100%
OnDisable()0%2100%
Update()0%6200%
OnDidApplyAnimationProperties()0%2100%
UpdateCachedReferences()0%1101000%
SetLow(...)0%110100%
SetLow(...)0%6.64045.45%
SetHigh(...)0%110100%
SetHigh(...)0%6.64045.45%
OnRectTransformDimensionsChange()0%2.262060%
UpdateVisuals()0%30500%
UpdateDrag(...)0%30500%
CalculateDrag(...)0%30500%
CalculateBarDrag(...)0%72800%
MayDrag(...)0%12300%
OnPointerDown(...)0%1321100%
OnDrag(...)0%6200%
OnPointerUp(...)0%2100%
OnMove(...)0%2100%
OnInitializePotentialDrag(...)0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/UIComponents/Scripts/Components/RangeSlider/RangeSlider.cs

#LineLine coverage
 1using System;
 2using UnityEngine;
 3using UnityEngine.Events;
 4using UnityEngine.EventSystems;
 5using UnityEngine.UI;
 6
 7namespace UIComponents.Scripts.Components.RangeSlider
 8{
 9    /// <summary>
 10    /// Credit Ben MacKinnon @Dover8
 11    /// Sourced from - https://github.com/Dover8/Unity-UI-Extensions/tree/range-slider
 12    /// Usage: Extension of the standard slider. Two handles determine a low and high value between a Min and Max.
 13    /// Raises a UnityEvent passing the low and high values
 14    /// </summary>
 15    [AddComponentMenu("UI/Range Slider", 34)]
 16    [ExecuteInEditMode]
 17    [RequireComponent(typeof(RectTransform))]
 18    public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
 19    {
 20        [Serializable]
 21        public class RangeSliderEvent : UnityEvent<float, float> { }
 22
 23        [SerializeField]
 24        private RectTransform m_FillRect;
 25
 026        public RectTransform FillRect { get { return m_FillRect; } set { if (SetClass(ref m_FillRect, value)) { UpdateCa
 27
 28        [SerializeField]
 29        private RectTransform m_LowHandleRect;
 30
 031        public RectTransform LowHandleRect { get { return m_LowHandleRect; } set { if (SetClass(ref m_LowHandleRect, val
 32
 33        [SerializeField]
 34        private RectTransform m_HighHandleRect;
 35
 036        public RectTransform HighHandleRect { get { return m_HighHandleRect; } set { if (SetClass(ref m_HighHandleRect, 
 37
 38        [Space]
 39
 40        [SerializeField]
 41        private float m_MinValue = 0;
 42
 20743        public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetLow(m_LowVal
 44
 45
 46        [SerializeField]
 5447        private float m_MaxValue = 1;
 48
 20749        public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetLow(m_LowVal
 50
 51        [SerializeField]
 52        private bool m_WholeNumbers = false;
 53
 63354        public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetL
 55
 56        [SerializeField]
 57        private float m_LowValue;
 58        public virtual float LowValue
 59        {
 60            get
 61            {
 10562                if (WholeNumbers)
 63                {
 10564                    return Mathf.Round(m_LowValue);
 65                }
 66
 067                return m_LowValue;
 68            }
 69            set
 70            {
 10571                SetLow(value);
 10572            }
 73        }
 74
 75        public float NormalizedLowValue
 76        {
 77            get
 78            {
 079                if (Mathf.Approximately(MinValue, MaxValue))
 80                {
 081                    return 0;
 82                }
 083                return Mathf.InverseLerp(MinValue, MaxValue, LowValue);
 84            }
 85            set
 86            {
 087                this.LowValue = Mathf.Lerp(MinValue, MaxValue, value);
 088            }
 89        }
 90
 91
 92        [SerializeField]
 93        private float m_HighValue;
 94        public virtual float HighValue
 95        {
 96            get
 97            {
 10598                if (WholeNumbers)
 99                {
 105100                    return Mathf.Round(m_HighValue);
 101                }
 102
 0103                return m_HighValue;
 104            }
 105            set
 106            {
 105107                SetHigh(value);
 105108            }
 109        }
 110
 111        public float NormalizedHighValue
 112        {
 113            get
 114            {
 0115                if (Mathf.Approximately(MinValue, MaxValue))
 116                {
 0117                    return 0;
 118                }
 0119                return Mathf.InverseLerp(MinValue, MaxValue, HighValue);
 120            }
 121            set
 122            {
 0123                this.HighValue = Mathf.Lerp(MinValue, MaxValue, value);
 0124            }
 125        }
 126
 127        /// <summary>
 128        /// Set the value of the slider without invoking onValueChanged callback.
 129        /// </summary>
 130        /// <param name="input">The new value for the slider.</param>
 131        public virtual void SetValueWithoutNotify(float low, float high)
 132        {
 0133            SetLow(low, false);
 0134            SetHigh(high, false);
 0135        }
 136
 137        [Space]
 138
 139        [SerializeField]
 54140        private RangeSliderEvent m_OnValueChanged = new RangeSliderEvent();
 141
 155142        public RangeSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
 143
 144        // Private fields
 145
 146        /// <summary>
 147        /// An Enum that says in what state we and interacting with the slider
 148        /// </summary>
 149        private enum InteractionState
 150        {
 151            Low,
 152            High,
 153            Bar,
 154            None
 155        }
 156
 54157        private InteractionState interactionState = InteractionState.None;
 158
 159        private Image m_FillImage;
 160        private Transform m_FillTransform;
 161        private RectTransform m_FillContainerRect;
 162        private Transform m_HighHandleTransform;
 163        private RectTransform m_HighHandleContainerRect;
 164        private Transform m_LowHandleTransform;
 165        private RectTransform m_LowHandleContainerRect;
 166
 167        // The offset from handle position to mouse down position
 54168        private Vector2 m_LowOffset = Vector2.zero;
 169        // The offset from handle position to mouse down position
 54170        private Vector2 m_HighOffset = Vector2.zero;
 171
 172        private DrivenRectTransformTracker m_Tracker;
 173
 174        // This "delayed" mechanism is required for case 1037681.
 175        private bool m_DelayedUpdateVisuals = false;
 176
 177        // Size of each step.
 0178        float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
 179
 54180        protected RangeSlider()
 54181        { }
 182
 183#if UNITY_EDITOR
 184        protected override void OnValidate()
 185        {
 3186            base.OnValidate();
 187
 3188            if (WholeNumbers)
 189            {
 3190                m_MinValue = Mathf.Round(m_MinValue);
 3191                m_MaxValue = Mathf.Round(m_MaxValue);
 192            }
 193
 3194            if (IsActive())
 195            {
 0196                UpdateCachedReferences();
 0197                SetLow(m_LowValue, false);
 0198                SetHigh(m_HighValue, false);
 199                //Update rects since other things might affect them even if value didn't change
 0200                m_DelayedUpdateVisuals = true;
 201            }
 202
 3203            if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
 204            {
 0205                CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
 206            }
 3207        }
 208#endif
 209
 210        public virtual void Rebuild(CanvasUpdate executing)
 211        {
 212#if UNITY_EDITOR
 0213            if (executing == CanvasUpdate.Prelayout)
 214            {
 0215                OnValueChanged.Invoke(LowValue, HighValue);
 216            }
 217#endif
 0218        }
 219
 220        /// <summary>
 221        /// See ICanvasElement.LayoutComplete
 222        /// </summary>
 223        public virtual void LayoutComplete()
 0224        { }
 225
 226        /// <summary>
 227        /// See ICanvasElement.GraphicUpdateComplete
 228        /// </summary>
 229        public virtual void GraphicUpdateComplete()
 0230        { }
 231
 232        public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
 233        {
 0234            if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
 0235                return false;
 236
 0237            currentValue = newValue;
 0238            return true;
 239        }
 240
 241        public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
 242        {
 207243            if (currentValue.Equals(newValue))
 207244                return false;
 245
 0246            currentValue = newValue;
 0247            return true;
 248        }
 249
 250        protected override void OnEnable()
 251        {
 0252            base.OnEnable();
 0253            UpdateCachedReferences();
 0254            SetLow(LowValue, false);
 0255            SetHigh(HighValue, false);
 256            // Update rects since they need to be initialized correctly.
 0257            UpdateVisuals();
 0258        }
 259
 260        protected override void OnDisable()
 261        {
 0262            m_Tracker.Clear();
 0263            base.OnDisable();
 0264        }
 265
 266        /// <summary>
 267        /// Update the rect based on the delayed update visuals.
 268        /// Got around issue of calling sendMessage from onValidate.
 269        /// </summary>
 270        protected virtual void Update()
 271        {
 0272            if (m_DelayedUpdateVisuals)
 273            {
 0274                m_DelayedUpdateVisuals = false;
 0275                UpdateVisuals();
 276            }
 0277        }
 278
 279        protected override void OnDidApplyAnimationProperties()
 280        {
 0281            base.OnDidApplyAnimationProperties();
 0282        }
 283
 284        void UpdateCachedReferences()
 285        {
 0286            if (m_FillRect && m_FillRect != (RectTransform)transform)
 287            {
 0288                m_FillTransform = m_FillRect.transform;
 0289                m_FillImage = m_FillRect.GetComponent<Image>();
 0290                if (m_FillTransform.parent != null)
 0291                    m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>();
 292            }
 293            else
 294            {
 0295                m_FillRect = null;
 0296                m_FillContainerRect = null;
 0297                m_FillImage = null;
 298            }
 299
 0300            if (m_HighHandleRect && m_HighHandleRect != (RectTransform)transform)
 301            {
 0302                m_HighHandleTransform = m_HighHandleRect.transform;
 0303                if (m_HighHandleTransform.parent != null)
 0304                    m_HighHandleContainerRect = m_HighHandleTransform.parent.GetComponent<RectTransform>();
 305            }
 306            else
 307            {
 0308                m_HighHandleRect = null;
 0309                m_HighHandleContainerRect = null;
 310            }
 311
 0312            if (m_LowHandleRect && m_LowHandleRect != (RectTransform)transform)
 313            {
 0314                m_LowHandleTransform = m_LowHandleRect.transform;
 0315                if (m_LowHandleTransform.parent != null)
 316                {
 0317                    m_LowHandleContainerRect = m_LowHandleTransform.parent.GetComponent<RectTransform>();
 318                }
 319            }
 320            else
 321            {
 0322                m_LowHandleRect = null;
 0323                m_LowHandleContainerRect = null;
 324            }
 0325        }
 326
 327        void SetLow(float input)
 328        {
 105329            SetLow(input, true);
 105330        }
 331
 332        protected virtual void SetLow(float input, bool sendCallback)
 333        {
 334            // Clamp the input
 105335            float newValue = Mathf.Clamp(input, MinValue, HighValue); //clamp between min and High
 105336            if (WholeNumbers)
 337            {
 105338                newValue = Mathf.Round(newValue);
 339            }
 340
 341            // If the stepped value doesn't match the last one, it's time to update
 105342            if (m_LowValue == newValue)
 105343                return;
 344
 0345            m_LowValue = newValue;
 0346            UpdateVisuals();
 0347            if (sendCallback)
 348            {
 0349                UISystemProfilerApi.AddMarker("RangeSlider.lowValue", this);
 0350                m_OnValueChanged.Invoke(newValue, HighValue);
 351            }
 0352        }
 353
 354        void SetHigh(float input)
 355        {
 105356            SetHigh(input, true);
 105357        }
 358
 359        protected virtual void SetHigh(float input, bool sendCallback)
 360        {
 361            // Clamp the input
 105362            float newValue = Mathf.Clamp(input, LowValue, MaxValue); //clamp between min and High
 105363            if (WholeNumbers)
 364            {
 105365                newValue = Mathf.Round(newValue);
 366            }
 367
 368            // If the stepped value doesn't match the last one, it's time to update
 105369            if (m_HighValue == newValue)
 105370                return;
 371
 0372            m_HighValue = newValue;
 0373            UpdateVisuals();
 0374            if (sendCallback)
 375            {
 0376                UISystemProfilerApi.AddMarker("RangeSlider.highValue", this);
 0377                m_OnValueChanged.Invoke(LowValue, newValue);
 378            }
 0379        }
 380
 381
 382        protected override void OnRectTransformDimensionsChange()
 383        {
 277384            base.OnRectTransformDimensionsChange();
 385
 386            //This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnabl
 277387            if (!IsActive())
 277388                return;
 389
 0390            UpdateVisuals();
 0391        }
 392
 393
 394        // Force-update the slider. Useful if you've changed the properties and want it to update visually.
 395        private void UpdateVisuals()
 396        {
 397#if UNITY_EDITOR
 0398            if (!Application.isPlaying)
 0399                UpdateCachedReferences();
 400#endif
 401
 0402            m_Tracker.Clear();
 403
 0404            if (m_FillContainerRect != null)
 405            {
 0406                m_Tracker.Add(this, m_FillRect, DrivenTransformProperties.Anchors);
 0407                Vector2 anchorMin = Vector2.zero;
 0408                Vector2 anchorMax = Vector2.one;
 409
 410                //this is where some new magic must happen. Slider just uses a filled image
 411                //and changes the % of fill. We must move the image anchors to be between the two handles.
 0412                anchorMin[0] = NormalizedLowValue;
 0413                anchorMax[0] = NormalizedHighValue;
 414
 0415                m_FillRect.anchorMin = anchorMin;
 0416                m_FillRect.anchorMax = anchorMax;
 417            }
 418
 0419            if (m_LowHandleContainerRect != null)
 420            {
 0421                m_Tracker.Add(this, m_LowHandleRect, DrivenTransformProperties.Anchors);
 0422                Vector2 anchorMin = Vector2.zero;
 0423                Vector2 anchorMax = Vector2.one;
 0424                anchorMin[0] = anchorMax[0] = NormalizedLowValue;
 0425                m_LowHandleRect.anchorMin = anchorMin;
 0426                m_LowHandleRect.anchorMax = anchorMax;
 427            }
 428
 0429            if (m_HighHandleContainerRect != null)
 430            {
 0431                m_Tracker.Add(this, m_HighHandleRect, DrivenTransformProperties.Anchors);
 0432                Vector2 anchorMin = Vector2.zero;
 0433                Vector2 anchorMax = Vector2.one;
 0434                anchorMin[0] = anchorMax[0] = NormalizedHighValue;
 0435                m_HighHandleRect.anchorMin = anchorMin;
 0436                m_HighHandleRect.anchorMax = anchorMax;
 437            }
 0438        }
 439
 440        // Update the slider's position based on the mouse.
 441        void UpdateDrag(PointerEventData eventData, Camera cam)
 442        {
 443            //this needs to differ from slider in that we have two handles, and need to move the right one.
 444            //and if it was neither handle, we will have a seperate case where both handles move uniformly
 445            //moving the entire range
 446
 447            //this is where we use our interationState
 0448            switch (interactionState)
 449            {
 450                case InteractionState.Low:
 0451                    NormalizedLowValue = CalculateDrag(eventData, cam, m_LowHandleContainerRect, m_LowOffset);
 0452                    break;
 453                case InteractionState.High:
 0454                    NormalizedHighValue = CalculateDrag(eventData, cam, m_HighHandleContainerRect, m_HighOffset);
 0455                    break;
 456                case InteractionState.Bar:
 457                    //special case
 0458                    CalculateBarDrag(eventData, cam);
 459                    break;
 460                case InteractionState.None:
 461                    break;
 462            }
 0463        }
 464
 465        private float CalculateDrag(PointerEventData eventData, Camera cam, RectTransform containerRect, Vector2 offset)
 466        {
 0467            RectTransform clickRect = containerRect ?? m_FillContainerRect;
 0468            if (clickRect != null && clickRect.rect.size[0] > 0)
 469            {
 470                Vector2 localCursor;
 0471                if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out loc
 472                {
 0473                    return 0f;
 474                }
 0475                localCursor -= clickRect.rect.position;
 476
 0477                float val = Mathf.Clamp01((localCursor - offset)[0] / clickRect.rect.size[0]);
 478
 0479                return val;
 480            }
 0481            return 0;
 482        }
 483
 484        private void CalculateBarDrag(PointerEventData eventData, Camera cam)
 485        {
 0486            RectTransform clickRect = m_FillContainerRect;
 0487            if (clickRect != null && clickRect.rect.size[0] > 0)
 488            {
 489                Vector2 localCursor;
 0490                if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out loc
 491                {
 0492                    return;
 493                }
 0494                localCursor -= clickRect.rect.position;
 495
 496                //now we need to get the delta drag on the bar
 497                //and move both the normalized low and high values by this amount
 498                //but also check that neither is going beyond the bounds
 0499                if (NormalizedLowValue >= 0 && NormalizedHighValue <= 1)
 500                {
 501                    //find the mid point on the current bar
 0502                    float mid = (NormalizedHighValue + NormalizedLowValue)/2;
 503                    //find where the new mid point should be
 0504                    float val = Mathf.Clamp01((localCursor)[0] / clickRect.rect.size[0]);
 505                    //calculate the delta
 0506                    float delta = val - mid;
 507                    //check the clamp range
 0508                    if (NormalizedLowValue + delta < 0)
 509                    {
 0510                        delta = -NormalizedLowValue;
 511                    }
 0512                    else if (NormalizedHighValue + delta > 1)
 513                    {
 0514                        delta = 1 - NormalizedHighValue;
 515                    }
 516
 517                    //adjust both ends
 0518                    NormalizedLowValue += delta;
 0519                    NormalizedHighValue += delta;
 520                }
 521            }
 0522        }
 523
 524        private bool MayDrag(PointerEventData eventData)
 525        {
 0526            return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
 527        }
 528
 529        public override void OnPointerDown(PointerEventData eventData)
 530        {
 0531            if (!MayDrag(eventData))
 0532                return;
 533
 534
 535            //HANDLE DRAG EVENTS
 0536            m_LowOffset = m_HighOffset = Vector2.zero;
 537            Vector2 localMousePos;
 0538            if (m_HighHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HighHandleRect, eventDat
 539            {
 540                //dragging the high value handle
 0541                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HighHandleRect, eventData.position, eventD
 542                {
 0543                    m_HighOffset = localMousePos;
 544                }
 0545                interactionState = InteractionState.High;
 0546                if (transition == Transition.ColorTint)
 547                {
 0548                    targetGraphic = m_HighHandleRect.GetComponent<Graphic>();
 549                }
 550            }
 0551            else if (m_LowHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_LowHandleRect, event
 552            {
 553                //dragging the low value handle
 0554                if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_LowHandleRect, eventData.position, eventDa
 555                {
 0556                    m_LowOffset = localMousePos;
 557                }
 0558                interactionState = InteractionState.Low;
 0559                if (transition == Transition.ColorTint)
 560                {
 0561                    targetGraphic = m_LowHandleRect.GetComponent<Graphic>();
 562                }
 563            }
 564            else
 565            {
 566                //outside the handles, move the entire slider along
 0567                UpdateDrag(eventData, eventData.pressEventCamera);
 0568                interactionState = InteractionState.Bar;
 0569                if (transition == Transition.ColorTint)
 570                {
 0571                    targetGraphic = m_FillImage;
 572                }
 573            }
 0574            base.OnPointerDown(eventData);
 0575        }
 576
 577        public virtual void OnDrag(PointerEventData eventData)
 578        {
 0579            if (!MayDrag(eventData))
 580            {
 0581                return;
 582            }
 0583            UpdateDrag(eventData, eventData.pressEventCamera);
 0584        }
 585
 586        public override void OnPointerUp(PointerEventData eventData)
 587        {
 0588            base.OnPointerUp(eventData);
 0589            interactionState = InteractionState.None;
 0590        }
 591
 592        public override void OnMove(AxisEventData eventData)
 593        {
 594            //this requires further investigation
 0595        }
 596
 597        public virtual void OnInitializePotentialDrag(PointerEventData eventData)
 598        {
 0599            eventData.useDragThreshold = false;
 0600        }
 601    }
 602}

Methods/Properties

FillRect()
FillRect(UnityEngine.RectTransform)
LowHandleRect()
LowHandleRect(UnityEngine.RectTransform)
HighHandleRect()
HighHandleRect(UnityEngine.RectTransform)
MinValue()
MinValue(System.Single)
RangeSlider()
MaxValue()
MaxValue(System.Single)
WholeNumbers()
WholeNumbers(System.Boolean)
LowValue()
LowValue(System.Single)
NormalizedLowValue()
NormalizedLowValue(System.Single)
HighValue()
HighValue(System.Single)
NormalizedHighValue()
NormalizedHighValue(System.Single)
SetValueWithoutNotify(System.Single, System.Single)
OnValueChanged()
OnValueChanged(UIComponents.Scripts.Components.RangeSlider.RangeSlider/RangeSliderEvent)
StepSize()
OnValidate()
Rebuild(UnityEngine.UI.CanvasUpdate)
LayoutComplete()
GraphicUpdateComplete()
SetClass[T](, T)
SetStruct[T](, T)
OnEnable()
OnDisable()
Update()
OnDidApplyAnimationProperties()
UpdateCachedReferences()
SetLow(System.Single)
SetLow(System.Single, System.Boolean)
SetHigh(System.Single)
SetHigh(System.Single, System.Boolean)
OnRectTransformDimensionsChange()
UpdateVisuals()
UpdateDrag(UnityEngine.EventSystems.PointerEventData, UnityEngine.Camera)
CalculateDrag(UnityEngine.EventSystems.PointerEventData, UnityEngine.Camera, UnityEngine.RectTransform, UnityEngine.Vector2)
CalculateBarDrag(UnityEngine.EventSystems.PointerEventData, UnityEngine.Camera)
MayDrag(UnityEngine.EventSystems.PointerEventData)
OnPointerDown(UnityEngine.EventSystems.PointerEventData)
OnDrag(UnityEngine.EventSystems.PointerEventData)
OnPointerUp(UnityEngine.EventSystems.PointerEventData)
OnMove(UnityEngine.EventSystems.AxisEventData)
OnInitializePotentialDrag(UnityEngine.EventSystems.PointerEventData)