Squashed commit of the following:
commit 6c5cf2dc036cf385b81fdfc8072300704b06b435 Merge:pull/413/headfb991af
bf30261 Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Tue Nov 12 17:54:34 2019 +0000 Merge branch 'refs/heads/master' into range-slider commit bf302616b8ae377a859d2012b856dc370efe40c2 Merge:10919c6
76d2299 Author: Ben MacKinnon <bilmackinnon@googlemail.com> Date: Tue Nov 12 17:44:57 2019 +0000 Merge pull request #1 from Dover8/range-slider Range slider commit 76d22998d38801ab35ba19743d944263041924a5 Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Tue Nov 12 17:36:23 2019 +0000 Updated PointerDown to update the target graphic Re-enabling colour tint interaction. commit 2d2ca219d5c0865ba4eaa428e8a167118aa06360 Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Tue Nov 12 16:59:29 2019 +0000 Updated headers to match the standard format of the project commit 9a0d3f4aaddbcee2565693b0733c0001a2de2a90 Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Tue Nov 12 16:43:22 2019 +0000 Some further default value set when creating a RangeSlider commit 748d1484568e16aa0bd2e3949330e48ce7245570 Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Tue Nov 12 16:38:34 2019 +0000 Added the menu creation options for the Range Slider commit fa9e9beceede8c708529cd6a3ea98673b2d6d2c2 Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Tue Nov 12 12:55:38 2019 +0000 Editor layout for the Range Slider Using the EditorGUILayout.MinMaxSlider to control the RangeSlider. It was this control that we are replicating in the UI. commit 32b731548e8e7f286964a4a7a35fd945e5d5a31a Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Mon Nov 11 16:19:16 2019 +0000 Updated namespace and header commit 4d0fa2e7dc535b343cf10def6e01886383cc88ac Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Mon Sep 16 12:41:45 2019 +0100 Added interaction Range slider is now interactable with both handles and the bar commit f4be93752719a08b95594e545eb16b27d3b3bcea Author: Ben MacKinnon <ben.mackinnon@soluis.com> Date: Fri Sep 13 15:27:15 2019 +0100 copied over the WIP RangeSlider from current project
parent
fb991af4ee
commit
8ef328fad3
|
@ -0,0 +1,123 @@
|
||||||
|
/// Credit Ben MacKinnon @Dover8
|
||||||
|
/// Sourced from - https://github.com/Dover8/Unity-UI-Extensions/tree/range-slider
|
||||||
|
/// Usage: Extension of the standard slider. Two handles determine a low and high value between a Min and Max.
|
||||||
|
/// Raises a UnityEvent passing the low and high values
|
||||||
|
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.UI;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(RangeSlider), true)]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
public class RangeSliderEditor : SelectableEditor
|
||||||
|
{
|
||||||
|
SerializedProperty m_LowHandleRect;
|
||||||
|
SerializedProperty m_HighHandleRect;
|
||||||
|
SerializedProperty m_FillRect;
|
||||||
|
|
||||||
|
SerializedProperty m_MinValue;
|
||||||
|
SerializedProperty m_MaxValue;
|
||||||
|
SerializedProperty m_WholeNumbers;
|
||||||
|
|
||||||
|
SerializedProperty m_LowValue;
|
||||||
|
SerializedProperty m_HighValue;
|
||||||
|
|
||||||
|
//need ref values for the editor MinMaxSlider
|
||||||
|
float low = 0;
|
||||||
|
float high = 1;
|
||||||
|
|
||||||
|
SerializedProperty m_OnValueChanged;
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
base.OnEnable();
|
||||||
|
m_LowHandleRect = serializedObject.FindProperty("m_LowHandleRect");
|
||||||
|
m_HighHandleRect = serializedObject.FindProperty("m_HighHandleRect");
|
||||||
|
m_FillRect = serializedObject.FindProperty("m_FillRect");
|
||||||
|
|
||||||
|
m_MinValue = serializedObject.FindProperty("m_MinValue");
|
||||||
|
m_MaxValue = serializedObject.FindProperty("m_MaxValue");
|
||||||
|
m_WholeNumbers = serializedObject.FindProperty("m_WholeNumbers");
|
||||||
|
|
||||||
|
m_LowValue = serializedObject.FindProperty("m_LowValue");
|
||||||
|
low = m_LowValue.floatValue;
|
||||||
|
m_HighValue = serializedObject.FindProperty("m_HighValue");
|
||||||
|
high = m_HighValue.floatValue;
|
||||||
|
|
||||||
|
m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
serializedObject.Update();
|
||||||
|
//grab the updated value affected by m_WholeNumbers
|
||||||
|
low = m_LowValue.floatValue;
|
||||||
|
high = m_HighValue.floatValue;
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(m_LowHandleRect);
|
||||||
|
EditorGUILayout.PropertyField(m_HighHandleRect);
|
||||||
|
EditorGUILayout.PropertyField(m_FillRect);
|
||||||
|
|
||||||
|
if (m_LowHandleRect.objectReferenceValue != null && m_HighHandleRect.objectReferenceValue != null)
|
||||||
|
{
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(m_MinValue);
|
||||||
|
EditorGUILayout.PropertyField(m_MaxValue);
|
||||||
|
EditorGUILayout.PropertyField(m_WholeNumbers);
|
||||||
|
|
||||||
|
//We're going to do a fair bit of layout here
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
//Low Label and value
|
||||||
|
EditorGUILayout.BeginVertical();
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
GUILayout.Label("Low");
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
low = EditorGUILayout.DelayedFloatField(low, GUILayout.MaxWidth(100));
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
//Slider
|
||||||
|
EditorGUILayout.BeginVertical();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.MinMaxSlider(ref low, ref high, m_MinValue.floatValue, m_MaxValue.floatValue, GUILayout.ExpandWidth(true));
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
//High label and value
|
||||||
|
EditorGUILayout.BeginVertical();
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
GUILayout.Label("High");
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
high = EditorGUILayout.DelayedFloatField(high, GUILayout.MaxWidth(100));
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
m_LowValue.floatValue = low;
|
||||||
|
m_HighValue.floatValue = high;
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
EditorGUILayout.PropertyField(m_OnValueChanged);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("Specify a RectTransform for the RangeSlider fill or the RangeSlider handles or both. Each must have a parent RectTransform that it can slide within.", MessageType.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ac33445ed95315743983e4b657921146
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1927,6 +1927,74 @@ namespace UnityEditor.UI
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region RangeSlider
|
||||||
|
[MenuItem("GameObject/UI/Extensions/RangeSlider", false)]
|
||||||
|
static public void AddRangeSlider(MenuCommand menuCommand)
|
||||||
|
{
|
||||||
|
GameObject rangeSliderRoot = CreateUIElementRoot("Range Slider", menuCommand, new Vector2(160, 20));
|
||||||
|
|
||||||
|
GameObject background = CreateUIObject("Background", rangeSliderRoot);
|
||||||
|
|
||||||
|
GameObject fillArea = CreateUIObject("Fill Area", rangeSliderRoot);
|
||||||
|
GameObject fill = CreateUIObject("Fill", fillArea);
|
||||||
|
|
||||||
|
GameObject handleSlideArea = CreateUIObject("Handle Slide Area", rangeSliderRoot);
|
||||||
|
GameObject lowHandle = CreateUIObject("Low Handle", handleSlideArea);
|
||||||
|
GameObject highHandle = CreateUIObject("High Handle", handleSlideArea);
|
||||||
|
|
||||||
|
SetAnchorsAndStretch(rangeSliderRoot);
|
||||||
|
Image backgroundImage = background.AddComponent<Image>();
|
||||||
|
backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
|
||||||
|
backgroundImage.type = Image.Type.Sliced;
|
||||||
|
backgroundImage.fillCenter = false;
|
||||||
|
|
||||||
|
RectTransform backgroundRect = backgroundImage.rectTransform;
|
||||||
|
backgroundRect.anchorMin = new Vector2(0, 0.25f);
|
||||||
|
backgroundRect.anchorMax = new Vector2(1, 0.75f);
|
||||||
|
backgroundRect.sizeDelta = Vector2.zero;
|
||||||
|
|
||||||
|
RectTransform fillAreaRect = SetAnchorsAndStretch(fillArea);
|
||||||
|
fillAreaRect.anchorMin = new Vector2(0, 0.25f);
|
||||||
|
fillAreaRect.anchorMax = new Vector2(1, 0.75f);
|
||||||
|
fillAreaRect.offsetMin = new Vector2(5, 0);
|
||||||
|
fillAreaRect.offsetMax = new Vector2(-5, 0);
|
||||||
|
|
||||||
|
RectTransform fillRect = SetAnchorsAndStretch(fill);
|
||||||
|
Image fillImage = fill.AddComponent<Image>();
|
||||||
|
fillImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
|
||||||
|
fillImage.type = Image.Type.Sliced;
|
||||||
|
fillImage.fillCenter = true;
|
||||||
|
fillRect.offsetMin = new Vector2(-5, 0);
|
||||||
|
fillRect.offsetMax = new Vector2(5, 0);
|
||||||
|
|
||||||
|
RectTransform handleSlideRect = SetAnchorsAndStretch(handleSlideArea);
|
||||||
|
handleSlideRect.anchorMin = new Vector2(0, 0.5f);
|
||||||
|
handleSlideRect.anchorMax = new Vector2(1, 0.5f);
|
||||||
|
handleSlideRect.offsetMin = new Vector2(10, -10);
|
||||||
|
handleSlideRect.offsetMax = new Vector2(-10, 10);
|
||||||
|
|
||||||
|
RectTransform lowHandleRect = SetAnchorsAndStretch(lowHandle);
|
||||||
|
Image lowHandleImage = lowHandle.AddComponent<Image>();
|
||||||
|
lowHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
||||||
|
lowHandleRect.sizeDelta = new Vector2(20, 0);
|
||||||
|
|
||||||
|
RectTransform highHandleRect = SetAnchorsAndStretch(highHandle);
|
||||||
|
Image highHandleImage = highHandle.AddComponent<Image>();
|
||||||
|
highHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
||||||
|
highHandleRect.sizeDelta = new Vector2(20, 0);
|
||||||
|
|
||||||
|
RangeSlider rangeSlider = rangeSliderRoot.AddComponent<RangeSlider>();
|
||||||
|
rangeSlider.FillRect = fillRect;
|
||||||
|
rangeSlider.LowHandleRect = lowHandleRect;
|
||||||
|
rangeSlider.HighHandleRect = highHandleRect;
|
||||||
|
rangeSlider.LowValue = rangeSlider.MinValue;
|
||||||
|
rangeSlider.HighValue = rangeSlider.MaxValue;
|
||||||
|
rangeSlider.targetGraphic = fillImage;
|
||||||
|
|
||||||
|
Selection.activeGameObject = rangeSliderRoot;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Menu Manager GO
|
#region Menu Manager GO
|
||||||
[MenuItem("GameObject/UI/Extensions/Menu Manager", false)]
|
[MenuItem("GameObject/UI/Extensions/Menu Manager", false)]
|
||||||
static public void AddMenuManager(MenuCommand menuCommand)
|
static public void AddMenuManager(MenuCommand menuCommand)
|
||||||
|
|
|
@ -0,0 +1,600 @@
|
||||||
|
/// Credit Ben MacKinnon @Dover8
|
||||||
|
/// Sourced from - https://github.com/Dover8/Unity-UI-Extensions/tree/range-slider
|
||||||
|
/// Usage: Extension of the standard slider. Two handles determine a low and high value between a Min and Max.
|
||||||
|
/// Raises a UnityEvent passing the low and high values
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
[AddComponentMenu("UI/Range Slider", 34)]
|
||||||
|
[ExecuteInEditMode]
|
||||||
|
[RequireComponent(typeof(RectTransform))]
|
||||||
|
public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
||||||
|
{
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class RangeSliderEvent : UnityEvent<float, float> { }
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private RectTransform m_FillRect;
|
||||||
|
|
||||||
|
public RectTransform FillRect { get { return m_FillRect; } set { if (SetClass(ref m_FillRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private RectTransform m_LowHandleRect;
|
||||||
|
|
||||||
|
public RectTransform LowHandleRect { get { return m_LowHandleRect; } set { if (SetClass(ref m_LowHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private RectTransform m_HighHandleRect;
|
||||||
|
|
||||||
|
public RectTransform HighHandleRect { get { return m_HighHandleRect; } set { if (SetClass(ref m_HighHandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
|
||||||
|
|
||||||
|
[Space]
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private float m_MinValue = 0;
|
||||||
|
|
||||||
|
public float MinValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
|
||||||
|
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private float m_MaxValue = 1;
|
||||||
|
|
||||||
|
public float MaxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_WholeNumbers = false;
|
||||||
|
|
||||||
|
public bool WholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { SetLow(m_LowValue); SetHigh(m_HighValue); UpdateVisuals(); } } }
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private float m_LowValue;
|
||||||
|
public virtual float LowValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (WholeNumbers)
|
||||||
|
{
|
||||||
|
return Mathf.Round(m_LowValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_LowValue;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetLow(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float NormalizedLowValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Mathf.Approximately(MinValue, MaxValue))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Mathf.InverseLerp(MinValue, MaxValue, LowValue);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.LowValue = Mathf.Lerp(MinValue, MaxValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private float m_HighValue;
|
||||||
|
public virtual float HighValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (WholeNumbers)
|
||||||
|
{
|
||||||
|
return Mathf.Round(m_HighValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_HighValue;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetHigh(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float NormalizedHighValue
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Mathf.Approximately(MinValue, MaxValue))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Mathf.InverseLerp(MinValue, MaxValue, HighValue);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.HighValue = Mathf.Lerp(MinValue, MaxValue, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the value of the slider without invoking onValueChanged callback.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">The new value for the slider.</param>
|
||||||
|
public virtual void SetValueWithoutNotify(float low, float high)
|
||||||
|
{
|
||||||
|
SetLow(low, false);
|
||||||
|
SetHigh(high, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Space]
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private RangeSliderEvent m_OnValueChanged = new RangeSliderEvent();
|
||||||
|
|
||||||
|
public RangeSliderEvent OnValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
|
||||||
|
|
||||||
|
// Private fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An Enum that says in what state we and interacting with the slider
|
||||||
|
/// </summary>
|
||||||
|
private enum InteractionState
|
||||||
|
{
|
||||||
|
Low,
|
||||||
|
High,
|
||||||
|
Bar,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
private InteractionState interactionState = InteractionState.None;
|
||||||
|
|
||||||
|
private Image m_FillImage;
|
||||||
|
private Transform m_FillTransform;
|
||||||
|
private RectTransform m_FillContainerRect;
|
||||||
|
private Transform m_HighHandleTransform;
|
||||||
|
private RectTransform m_HighHandleContainerRect;
|
||||||
|
private Transform m_LowHandleTransform;
|
||||||
|
private RectTransform m_LowHandleContainerRect;
|
||||||
|
|
||||||
|
// The offset from handle position to mouse down position
|
||||||
|
private Vector2 m_LowOffset = Vector2.zero;
|
||||||
|
// The offset from handle position to mouse down position
|
||||||
|
private Vector2 m_HighOffset = Vector2.zero;
|
||||||
|
|
||||||
|
private DrivenRectTransformTracker m_Tracker;
|
||||||
|
|
||||||
|
// This "delayed" mechanism is required for case 1037681.
|
||||||
|
private bool m_DelayedUpdateVisuals = false;
|
||||||
|
|
||||||
|
// Size of each step.
|
||||||
|
float StepSize { get { return WholeNumbers ? 1 : (MaxValue - MinValue) * 0.1f; } }
|
||||||
|
|
||||||
|
protected RangeSlider()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
protected override void OnValidate()
|
||||||
|
{
|
||||||
|
base.OnValidate();
|
||||||
|
|
||||||
|
if (WholeNumbers)
|
||||||
|
{
|
||||||
|
m_MinValue = Mathf.Round(m_MinValue);
|
||||||
|
m_MaxValue = Mathf.Round(m_MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsActive())
|
||||||
|
{
|
||||||
|
UpdateCachedReferences();
|
||||||
|
SetLow(m_LowValue, false);
|
||||||
|
SetHigh(m_HighValue, false);
|
||||||
|
//Update rects since other things might affect them even if value didn't change
|
||||||
|
m_DelayedUpdateVisuals = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
|
||||||
|
{
|
||||||
|
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
public virtual void Rebuild(CanvasUpdate executing)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (executing == CanvasUpdate.Prelayout)
|
||||||
|
{
|
||||||
|
OnValueChanged.Invoke(LowValue, HighValue);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See ICanvasElement.LayoutComplete
|
||||||
|
/// </summary>
|
||||||
|
public virtual void LayoutComplete()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See ICanvasElement.GraphicUpdateComplete
|
||||||
|
/// </summary>
|
||||||
|
public virtual void GraphicUpdateComplete()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
|
||||||
|
{
|
||||||
|
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentValue = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
|
||||||
|
{
|
||||||
|
if (currentValue.Equals(newValue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentValue = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
base.OnEnable();
|
||||||
|
UpdateCachedReferences();
|
||||||
|
SetLow(LowValue, false);
|
||||||
|
SetHigh(HighValue, false);
|
||||||
|
// Update rects since they need to be initialized correctly.
|
||||||
|
UpdateVisuals();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDisable()
|
||||||
|
{
|
||||||
|
m_Tracker.Clear();
|
||||||
|
base.OnDisable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the rect based on the delayed update visuals.
|
||||||
|
/// Got around issue of calling sendMessage from onValidate.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void Update()
|
||||||
|
{
|
||||||
|
if (m_DelayedUpdateVisuals)
|
||||||
|
{
|
||||||
|
m_DelayedUpdateVisuals = false;
|
||||||
|
UpdateVisuals();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDidApplyAnimationProperties()
|
||||||
|
{
|
||||||
|
base.OnDidApplyAnimationProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateCachedReferences()
|
||||||
|
{
|
||||||
|
if (m_FillRect && m_FillRect != (RectTransform)transform)
|
||||||
|
{
|
||||||
|
m_FillTransform = m_FillRect.transform;
|
||||||
|
m_FillImage = m_FillRect.GetComponent<Image>();
|
||||||
|
if (m_FillTransform.parent != null)
|
||||||
|
m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_FillRect = null;
|
||||||
|
m_FillContainerRect = null;
|
||||||
|
m_FillImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_HighHandleRect && m_HighHandleRect != (RectTransform)transform)
|
||||||
|
{
|
||||||
|
m_HighHandleTransform = m_HighHandleRect.transform;
|
||||||
|
if (m_HighHandleTransform.parent != null)
|
||||||
|
m_HighHandleContainerRect = m_HighHandleTransform.parent.GetComponent<RectTransform>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_HighHandleRect = null;
|
||||||
|
m_HighHandleContainerRect = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_LowHandleRect && m_LowHandleRect != (RectTransform)transform)
|
||||||
|
{
|
||||||
|
m_LowHandleTransform = m_LowHandleRect.transform;
|
||||||
|
if (m_LowHandleTransform.parent != null)
|
||||||
|
{
|
||||||
|
m_LowHandleContainerRect = m_LowHandleTransform.parent.GetComponent<RectTransform>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_LowHandleRect = null;
|
||||||
|
m_LowHandleContainerRect = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetLow(float input)
|
||||||
|
{
|
||||||
|
SetLow(input, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void SetLow(float input, bool sendCallback)
|
||||||
|
{
|
||||||
|
// Clamp the input
|
||||||
|
float newValue = Mathf.Clamp(input, MinValue, HighValue); //clamp between min and High
|
||||||
|
if (WholeNumbers)
|
||||||
|
{
|
||||||
|
newValue = Mathf.Round(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the stepped value doesn't match the last one, it's time to update
|
||||||
|
if (m_LowValue == newValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_LowValue = newValue;
|
||||||
|
UpdateVisuals();
|
||||||
|
if (sendCallback)
|
||||||
|
{
|
||||||
|
UISystemProfilerApi.AddMarker("RangeSlider.lowValue", this);
|
||||||
|
m_OnValueChanged.Invoke(newValue, HighValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHigh(float input)
|
||||||
|
{
|
||||||
|
SetHigh(input, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void SetHigh(float input, bool sendCallback)
|
||||||
|
{
|
||||||
|
// Clamp the input
|
||||||
|
float newValue = Mathf.Clamp(input, LowValue, MaxValue); //clamp between min and High
|
||||||
|
if (WholeNumbers)
|
||||||
|
{
|
||||||
|
newValue = Mathf.Round(newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the stepped value doesn't match the last one, it's time to update
|
||||||
|
if (m_HighValue == newValue)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_HighValue = newValue;
|
||||||
|
UpdateVisuals();
|
||||||
|
if (sendCallback)
|
||||||
|
{
|
||||||
|
UISystemProfilerApi.AddMarker("RangeSlider.highValue", this);
|
||||||
|
m_OnValueChanged.Invoke(LowValue, newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected override void OnRectTransformDimensionsChange()
|
||||||
|
{
|
||||||
|
base.OnRectTransformDimensionsChange();
|
||||||
|
|
||||||
|
//This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
|
||||||
|
if (!IsActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
UpdateVisuals();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Force-update the slider. Useful if you've changed the properties and want it to update visually.
|
||||||
|
private void UpdateVisuals()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
if (!Application.isPlaying)
|
||||||
|
UpdateCachedReferences();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_Tracker.Clear();
|
||||||
|
|
||||||
|
if (m_FillContainerRect != null)
|
||||||
|
{
|
||||||
|
m_Tracker.Add(this, m_FillRect, DrivenTransformProperties.Anchors);
|
||||||
|
Vector2 anchorMin = Vector2.zero;
|
||||||
|
Vector2 anchorMax = Vector2.one;
|
||||||
|
|
||||||
|
//this is where some new magic must happen. Slider just uses a filled image
|
||||||
|
//and changes the % of fill. We must move the image anchors to be between the two handles.
|
||||||
|
anchorMin[0] = NormalizedLowValue;
|
||||||
|
anchorMax[0] = NormalizedHighValue;
|
||||||
|
|
||||||
|
m_FillRect.anchorMin = anchorMin;
|
||||||
|
m_FillRect.anchorMax = anchorMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_LowHandleContainerRect != null)
|
||||||
|
{
|
||||||
|
m_Tracker.Add(this, m_LowHandleRect, DrivenTransformProperties.Anchors);
|
||||||
|
Vector2 anchorMin = Vector2.zero;
|
||||||
|
Vector2 anchorMax = Vector2.one;
|
||||||
|
anchorMin[0] = anchorMax[0] = NormalizedLowValue;
|
||||||
|
m_LowHandleRect.anchorMin = anchorMin;
|
||||||
|
m_LowHandleRect.anchorMax = anchorMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_HighHandleContainerRect != null)
|
||||||
|
{
|
||||||
|
m_Tracker.Add(this, m_HighHandleRect, DrivenTransformProperties.Anchors);
|
||||||
|
Vector2 anchorMin = Vector2.zero;
|
||||||
|
Vector2 anchorMax = Vector2.one;
|
||||||
|
anchorMin[0] = anchorMax[0] = NormalizedHighValue;
|
||||||
|
m_HighHandleRect.anchorMin = anchorMin;
|
||||||
|
m_HighHandleRect.anchorMax = anchorMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the slider's position based on the mouse.
|
||||||
|
void UpdateDrag(PointerEventData eventData, Camera cam)
|
||||||
|
{
|
||||||
|
//this needs to differ from slider in that we have two handles, and need to move the right one.
|
||||||
|
//and if it was neither handle, we will have a seperate case where both handles move uniformly
|
||||||
|
//moving the entire range
|
||||||
|
|
||||||
|
//this is where we use our interationState
|
||||||
|
switch (interactionState)
|
||||||
|
{
|
||||||
|
case InteractionState.Low:
|
||||||
|
NormalizedLowValue = CalculateDrag(eventData, cam, m_LowHandleContainerRect, m_LowOffset);
|
||||||
|
break;
|
||||||
|
case InteractionState.High:
|
||||||
|
NormalizedHighValue = CalculateDrag(eventData, cam, m_HighHandleContainerRect, m_HighOffset);
|
||||||
|
break;
|
||||||
|
case InteractionState.Bar:
|
||||||
|
//special case
|
||||||
|
CalculateBarDrag(eventData, cam);
|
||||||
|
break;
|
||||||
|
case InteractionState.None:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float CalculateDrag(PointerEventData eventData, Camera cam, RectTransform containerRect, Vector2 offset)
|
||||||
|
{
|
||||||
|
RectTransform clickRect = containerRect ?? m_FillContainerRect;
|
||||||
|
if (clickRect != null && clickRect.rect.size[0] > 0)
|
||||||
|
{
|
||||||
|
Vector2 localCursor;
|
||||||
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
|
||||||
|
{
|
||||||
|
return 0f;
|
||||||
|
}
|
||||||
|
localCursor -= clickRect.rect.position;
|
||||||
|
|
||||||
|
float val = Mathf.Clamp01((localCursor - offset)[0] / clickRect.rect.size[0]);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CalculateBarDrag(PointerEventData eventData, Camera cam)
|
||||||
|
{
|
||||||
|
RectTransform clickRect = m_FillContainerRect;
|
||||||
|
if (clickRect != null && clickRect.rect.size[0] > 0)
|
||||||
|
{
|
||||||
|
Vector2 localCursor;
|
||||||
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
localCursor -= clickRect.rect.position;
|
||||||
|
|
||||||
|
//now we need to get the delta drag on the bar
|
||||||
|
//and move both the normalized low and high values by this amount
|
||||||
|
//but also check that neither is going beyond the bounds
|
||||||
|
if (NormalizedLowValue >= 0 && NormalizedHighValue <= 1)
|
||||||
|
{
|
||||||
|
//find the mid point on the current bar
|
||||||
|
float mid = (NormalizedHighValue + NormalizedLowValue)/2;
|
||||||
|
//find where the new mid point should be
|
||||||
|
float val = Mathf.Clamp01((localCursor)[0] / clickRect.rect.size[0]);
|
||||||
|
//calculate the delta
|
||||||
|
float delta = val - mid;
|
||||||
|
//check the clamp range
|
||||||
|
if (NormalizedLowValue + delta < 0)
|
||||||
|
{
|
||||||
|
delta = -NormalizedLowValue;
|
||||||
|
}
|
||||||
|
else if (NormalizedHighValue + delta > 1)
|
||||||
|
{
|
||||||
|
delta = 1 - NormalizedHighValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//adjust both ends
|
||||||
|
NormalizedLowValue += delta;
|
||||||
|
NormalizedHighValue += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MayDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPointerDown(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!MayDrag(eventData))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
//HANDLE DRAG EVENTS
|
||||||
|
m_LowOffset = m_HighOffset = Vector2.zero;
|
||||||
|
Vector2 localMousePos;
|
||||||
|
if (m_HighHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HighHandleRect, eventData.position, eventData.enterEventCamera))
|
||||||
|
{
|
||||||
|
//dragging the high value handle
|
||||||
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HighHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
|
||||||
|
{
|
||||||
|
m_HighOffset = localMousePos;
|
||||||
|
}
|
||||||
|
interactionState = InteractionState.High;
|
||||||
|
if (transition == Transition.ColorTint)
|
||||||
|
{
|
||||||
|
targetGraphic = m_HighHandleRect.GetComponent<Graphic>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_LowHandleRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_LowHandleRect, eventData.position, eventData.enterEventCamera))
|
||||||
|
{
|
||||||
|
//dragging the low value handle
|
||||||
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_LowHandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
|
||||||
|
{
|
||||||
|
m_LowOffset = localMousePos;
|
||||||
|
}
|
||||||
|
interactionState = InteractionState.Low;
|
||||||
|
if (transition == Transition.ColorTint)
|
||||||
|
{
|
||||||
|
targetGraphic = m_LowHandleRect.GetComponent<Graphic>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//outside the handles, move the entire slider along
|
||||||
|
UpdateDrag(eventData, eventData.pressEventCamera);
|
||||||
|
interactionState = InteractionState.Bar;
|
||||||
|
if (transition == Transition.ColorTint)
|
||||||
|
{
|
||||||
|
targetGraphic = m_FillImage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base.OnPointerDown(eventData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (!MayDrag(eventData))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UpdateDrag(eventData, eventData.pressEventCamera);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnPointerUp(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
base.OnPointerUp(eventData);
|
||||||
|
interactionState = InteractionState.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnMove(AxisEventData eventData)
|
||||||
|
{
|
||||||
|
//this requires further investigation
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
eventData.useDragThreshold = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4735d2b59d5c699488c30a34a6a76e72
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Loading…
Reference in New Issue