parent
3ed20ecaed
commit
2848008f63
|
@ -0,0 +1,121 @@
|
||||||
|
///Credit brogan89
|
||||||
|
///Sourced from - https://github.com/brogan89/MinMaxSlider
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.UI;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(MinMaxSlider), true)]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
public class MinMaxSliderEditor : SelectableEditor
|
||||||
|
{
|
||||||
|
private SerializedProperty _customCamera;
|
||||||
|
private SerializedProperty _sliderBounds;
|
||||||
|
private SerializedProperty _minHandle;
|
||||||
|
private SerializedProperty _maxHandle;
|
||||||
|
private SerializedProperty _minText;
|
||||||
|
private SerializedProperty _maxText;
|
||||||
|
private SerializedProperty _textFormat;
|
||||||
|
private SerializedProperty _middleGraphic;
|
||||||
|
private SerializedProperty _minLimit;
|
||||||
|
private SerializedProperty _maxLimit;
|
||||||
|
private SerializedProperty _wholeNumbers;
|
||||||
|
private SerializedProperty _minValue;
|
||||||
|
private SerializedProperty _maxValue;
|
||||||
|
|
||||||
|
private SerializedProperty _onValueChanged;
|
||||||
|
|
||||||
|
private readonly GUIContent label = new GUIContent("Min Max Values");
|
||||||
|
|
||||||
|
protected override void OnEnable()
|
||||||
|
{
|
||||||
|
base.OnEnable();
|
||||||
|
_customCamera = serializedObject.FindProperty("customCamera");
|
||||||
|
_sliderBounds = serializedObject.FindProperty("sliderBounds");
|
||||||
|
_minHandle = serializedObject.FindProperty("minHandle");
|
||||||
|
_maxHandle = serializedObject.FindProperty("maxHandle");
|
||||||
|
_minText = serializedObject.FindProperty("minText");
|
||||||
|
_maxText = serializedObject.FindProperty("maxText");
|
||||||
|
_textFormat = serializedObject.FindProperty("textFormat");
|
||||||
|
_middleGraphic = serializedObject.FindProperty("middleGraphic");
|
||||||
|
_minLimit = serializedObject.FindProperty("minLimit");
|
||||||
|
_maxLimit = serializedObject.FindProperty("maxLimit");
|
||||||
|
_wholeNumbers = serializedObject.FindProperty("wholeNumbers");
|
||||||
|
_minValue = serializedObject.FindProperty("minValue");
|
||||||
|
_maxValue = serializedObject.FindProperty("maxValue");
|
||||||
|
_onValueChanged = serializedObject.FindProperty("onValueChanged");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
|
||||||
|
serializedObject.Update();
|
||||||
|
|
||||||
|
float minLimitOld = _minLimit.floatValue;
|
||||||
|
float maxLimitOld = _maxLimit.floatValue;
|
||||||
|
float minValueOld = _minValue.floatValue;
|
||||||
|
float maxValueOld = _maxValue.floatValue;
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_customCamera);
|
||||||
|
EditorGUILayout.PropertyField(_sliderBounds);
|
||||||
|
EditorGUILayout.PropertyField(_minHandle);
|
||||||
|
EditorGUILayout.PropertyField(_maxHandle);
|
||||||
|
EditorGUILayout.PropertyField(_middleGraphic);
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_minText);
|
||||||
|
EditorGUILayout.PropertyField(_maxText);
|
||||||
|
EditorGUILayout.PropertyField(_textFormat);
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_minLimit);
|
||||||
|
EditorGUILayout.PropertyField(_maxLimit);
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(_wholeNumbers);
|
||||||
|
EditorGUILayout.PropertyField(_minValue);
|
||||||
|
EditorGUILayout.PropertyField(_maxValue);
|
||||||
|
|
||||||
|
float minValue = Mathf.Clamp(_minValue.floatValue, _minLimit.floatValue, _maxLimit.floatValue);
|
||||||
|
float maxValue = Mathf.Clamp(_maxValue.floatValue, _minLimit.floatValue, _maxLimit.floatValue);
|
||||||
|
EditorGUILayout.MinMaxSlider(label, ref minValue, ref maxValue, _minLimit.floatValue, _maxLimit.floatValue);
|
||||||
|
|
||||||
|
bool anyValueChanged = !IsEqualFloat(minValueOld, minValue)
|
||||||
|
|| !IsEqualFloat(maxValueOld, maxValue)
|
||||||
|
|| !IsEqualFloat(minLimitOld, _minLimit.floatValue)
|
||||||
|
|| !IsEqualFloat(maxLimitOld, _maxLimit.floatValue);
|
||||||
|
|
||||||
|
if (anyValueChanged)
|
||||||
|
{
|
||||||
|
MinMaxSlider slider = (MinMaxSlider)target;
|
||||||
|
|
||||||
|
// force limits to ints if whole numbers.
|
||||||
|
// needed to do this here because it wouldn't set in component script for some reason
|
||||||
|
if (slider.wholeNumbers)
|
||||||
|
{
|
||||||
|
_minLimit.floatValue = Mathf.RoundToInt(_minLimit.floatValue);
|
||||||
|
_maxLimit.floatValue = Mathf.RoundToInt(_maxLimit.floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set slider values
|
||||||
|
slider.SetValues(minValue, maxValue, _minLimit.floatValue, _maxLimit.floatValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
EditorGUILayout.PropertyField(_onValueChanged);
|
||||||
|
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if floating point numbers are within 0.01f (close enough to be considered equal)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a"></param>
|
||||||
|
/// <param name="b"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static bool IsEqualFloat(float a, float b)
|
||||||
|
{
|
||||||
|
return Math.Abs(a - b) < 0.01f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 69352ed1561021b48ac258f81f48a988
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,4 +1,5 @@
|
||||||
using UnityEngine;
|
using TMPro;
|
||||||
|
using UnityEngine;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityEngine.UI.Extensions;
|
using UnityEngine.UI.Extensions;
|
||||||
|
@ -1847,7 +1848,7 @@ namespace UnityEditor.UI
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Stepper
|
#region Stepper
|
||||||
[MenuItem("GameObject/UI/Extensions/Stepper", false)]
|
[MenuItem("GameObject/UI/Extensions/Sliders/Stepper", false)]
|
||||||
static public void AddStepper(MenuCommand menuCommand)
|
static public void AddStepper(MenuCommand menuCommand)
|
||||||
{
|
{
|
||||||
GameObject go = CreateUIElementRoot("Stepper", menuCommand, new Vector2(kWidth / 2, kThickHeight));
|
GameObject go = CreateUIElementRoot("Stepper", menuCommand, new Vector2(kWidth / 2, kThickHeight));
|
||||||
|
@ -1891,7 +1892,7 @@ namespace UnityEditor.UI
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region BoxSlider
|
#region BoxSlider
|
||||||
[MenuItem("GameObject/UI/Extensions/Box Slider", false)]
|
[MenuItem("GameObject/UI/Extensions/Sliders/Box Slider", false)]
|
||||||
static public void AddBoxSlider(MenuCommand menuCommand)
|
static public void AddBoxSlider(MenuCommand menuCommand)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1946,7 +1947,7 @@ namespace UnityEditor.UI
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Radial Slider
|
#region Radial Slider
|
||||||
[MenuItem("GameObject/UI/Extensions/Radial Slider", false)]
|
[MenuItem("GameObject/UI/Extensions/Sliders/Radial Slider", false)]
|
||||||
static public void AddRadialSlider(MenuCommand menuCommand)
|
static public void AddRadialSlider(MenuCommand menuCommand)
|
||||||
{
|
{
|
||||||
GameObject sliderRoot = CreateUIElementRoot("Radial Slider", menuCommand, s_ThickGUIElementSize);
|
GameObject sliderRoot = CreateUIElementRoot("Radial Slider", menuCommand, s_ThickGUIElementSize);
|
||||||
|
@ -1984,21 +1985,21 @@ namespace UnityEditor.UI
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region RangeSlider
|
#region RangeSlider
|
||||||
[MenuItem("GameObject/UI/Extensions/Range Slider", false)]
|
[MenuItem("GameObject/UI/Extensions/Sliders/Range Slider", false)]
|
||||||
static public void AddRangeSlider(MenuCommand menuCommand)
|
static public void AddRangeSlider(MenuCommand menuCommand)
|
||||||
{
|
{
|
||||||
GameObject rangeSliderRoot = CreateUIElementRoot("Range Slider", menuCommand, new Vector2(160, 20));
|
GameObject minMaxSliderRoot = CreateUIElementRoot("Range Slider", menuCommand, new Vector2(160, 20));
|
||||||
|
|
||||||
GameObject background = CreateUIObject("Background", rangeSliderRoot);
|
GameObject background = CreateUIObject("Background", minMaxSliderRoot);
|
||||||
|
|
||||||
GameObject fillArea = CreateUIObject("Fill Area", rangeSliderRoot);
|
GameObject fillArea = CreateUIObject("Fill Area", minMaxSliderRoot);
|
||||||
GameObject fill = CreateUIObject("Fill", fillArea);
|
GameObject fill = CreateUIObject("Fill", fillArea);
|
||||||
|
|
||||||
GameObject handleSlideArea = CreateUIObject("Handle Slide Area", rangeSliderRoot);
|
GameObject handleSlideArea = CreateUIObject("Handle Slide Area", minMaxSliderRoot);
|
||||||
GameObject lowHandle = CreateUIObject("Low Handle", handleSlideArea);
|
GameObject minHandle = CreateUIObject("Low Handle", handleSlideArea);
|
||||||
GameObject highHandle = CreateUIObject("High Handle", handleSlideArea);
|
GameObject highHandle = CreateUIObject("High Handle", handleSlideArea);
|
||||||
|
|
||||||
SetAnchorsAndStretch(rangeSliderRoot);
|
SetAnchorsAndStretch(minMaxSliderRoot);
|
||||||
Image backgroundImage = background.AddComponent<Image>();
|
Image backgroundImage = background.AddComponent<Image>();
|
||||||
backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
|
backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kBackgroundSpriteResourcePath);
|
||||||
backgroundImage.type = Image.Type.Sliced;
|
backgroundImage.type = Image.Type.Sliced;
|
||||||
|
@ -2029,8 +2030,8 @@ namespace UnityEditor.UI
|
||||||
handleSlideRect.offsetMin = new Vector2(10, -10);
|
handleSlideRect.offsetMin = new Vector2(10, -10);
|
||||||
handleSlideRect.offsetMax = new Vector2(-10, 10);
|
handleSlideRect.offsetMax = new Vector2(-10, 10);
|
||||||
|
|
||||||
RectTransform lowHandleRect = SetAnchorsAndStretch(lowHandle);
|
RectTransform lowHandleRect = SetAnchorsAndStretch(minHandle);
|
||||||
Image lowHandleImage = lowHandle.AddComponent<Image>();
|
Image lowHandleImage = minHandle.AddComponent<Image>();
|
||||||
lowHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
lowHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
||||||
lowHandleRect.sizeDelta = new Vector2(20, 0);
|
lowHandleRect.sizeDelta = new Vector2(20, 0);
|
||||||
|
|
||||||
|
@ -2039,7 +2040,7 @@ namespace UnityEditor.UI
|
||||||
highHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
highHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kKnobPath);
|
||||||
highHandleRect.sizeDelta = new Vector2(20, 0);
|
highHandleRect.sizeDelta = new Vector2(20, 0);
|
||||||
|
|
||||||
RangeSlider rangeSlider = rangeSliderRoot.AddComponent<RangeSlider>();
|
RangeSlider rangeSlider = minMaxSliderRoot.AddComponent<RangeSlider>();
|
||||||
rangeSlider.FillRect = fillRect;
|
rangeSlider.FillRect = fillRect;
|
||||||
rangeSlider.LowHandleRect = lowHandleRect;
|
rangeSlider.LowHandleRect = lowHandleRect;
|
||||||
rangeSlider.HighHandleRect = highHandleRect;
|
rangeSlider.HighHandleRect = highHandleRect;
|
||||||
|
@ -2047,7 +2048,7 @@ namespace UnityEditor.UI
|
||||||
rangeSlider.HighValue = rangeSlider.MaxValue;
|
rangeSlider.HighValue = rangeSlider.MaxValue;
|
||||||
rangeSlider.targetGraphic = fillImage;
|
rangeSlider.targetGraphic = fillImage;
|
||||||
|
|
||||||
Selection.activeGameObject = rangeSliderRoot;
|
Selection.activeGameObject = minMaxSliderRoot;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
@ -2062,6 +2063,80 @@ namespace UnityEditor.UI
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region MinMaxSlider
|
||||||
|
[MenuItem("GameObject/UI/Extensions/Sliders/MinMax Slider", false)]
|
||||||
|
static public void AddMinMaxSlider(MenuCommand menuCommand)
|
||||||
|
{
|
||||||
|
GameObject minMaxSliderRoot = CreateUIElementRoot("MinMax Slider", menuCommand, new Vector2(390, 60));
|
||||||
|
|
||||||
|
//GameObject background = CreateUIObject("Background", rangeSliderRoot);
|
||||||
|
|
||||||
|
GameObject sliderBounds = CreateUIObject("Slider Bounds", minMaxSliderRoot);
|
||||||
|
GameObject middleGraphic = CreateUIObject("Middle Graphic", minMaxSliderRoot);
|
||||||
|
|
||||||
|
GameObject minHandle = CreateUIObject("Min Handle", minMaxSliderRoot);
|
||||||
|
GameObject minHandleText = CreateUIObject("Min Text", minHandle);
|
||||||
|
GameObject maxHandle = CreateUIObject("Max Handle", minMaxSliderRoot);
|
||||||
|
GameObject maxHandleText = CreateUIObject("Max Text", maxHandle);
|
||||||
|
|
||||||
|
SetAnchorsAndStretch(minMaxSliderRoot);
|
||||||
|
Image backgroundImage = minMaxSliderRoot.AddComponent<Image>();
|
||||||
|
backgroundImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
|
||||||
|
backgroundImage.type = Image.Type.Sliced;
|
||||||
|
backgroundImage.fillCenter = false;
|
||||||
|
backgroundImage.color = new Color(27, 41, 89);
|
||||||
|
|
||||||
|
RectTransform backgroundRect = backgroundImage.rectTransform;
|
||||||
|
backgroundRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||||
|
backgroundRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||||
|
backgroundRect.sizeDelta = Vector2.zero;
|
||||||
|
|
||||||
|
RectTransform sliderBoundsRect = SetAnchorsAndStretch(sliderBounds);
|
||||||
|
sliderBoundsRect.anchorMin = new Vector2(0, 0);
|
||||||
|
sliderBoundsRect.anchorMax = new Vector2(1, 1);
|
||||||
|
|
||||||
|
RectTransform middleGraphicRect = SetAnchorsAndStretch(middleGraphic);
|
||||||
|
Image fillImage = middleGraphic.AddComponent<Image>();
|
||||||
|
fillImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
|
||||||
|
fillImage.type = Image.Type.Sliced;
|
||||||
|
fillImage.fillCenter = true;
|
||||||
|
fillImage.color = new Color(41, 98, 164);
|
||||||
|
|
||||||
|
RectTransform minHandleRect = SetAnchorsAndStretch(minHandle);
|
||||||
|
Image lowHandleImage = minHandle.AddComponent<Image>();
|
||||||
|
lowHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
|
||||||
|
minHandleRect.sizeDelta = new Vector2(30, 62);
|
||||||
|
|
||||||
|
RectTransform minHandleTextRect = SetAnchorsAndStretch(minHandleText);
|
||||||
|
TextMeshProUGUI minHandleTextComponent = minHandleText.AddComponent<TextMeshProUGUI>();
|
||||||
|
minHandleTextComponent.text = "0";
|
||||||
|
minHandleTextComponent.fontSize = 36;
|
||||||
|
minHandleTextRect.sizeDelta = new Vector2(70, 50);
|
||||||
|
minHandleTextRect.position = new Vector3(0, -60,0);
|
||||||
|
|
||||||
|
RectTransform maxHandleRect = SetAnchorsAndStretch(maxHandle);
|
||||||
|
Image maxHandleImage = maxHandle.AddComponent<Image>();
|
||||||
|
maxHandleImage.sprite = AssetDatabase.GetBuiltinExtraResource<Sprite>(kStandardSpritePath);
|
||||||
|
maxHandleRect.sizeDelta = new Vector2(20, 0);
|
||||||
|
|
||||||
|
RectTransform maxHandleTextRect = SetAnchorsAndStretch(maxHandleText);
|
||||||
|
TextMeshProUGUI maxHandleTextComponent = maxHandleText.AddComponent<TextMeshProUGUI>();
|
||||||
|
maxHandleTextComponent.text = "0";
|
||||||
|
maxHandleTextComponent.fontSize = 36;
|
||||||
|
maxHandleTextRect.sizeDelta = new Vector2(70, 50);
|
||||||
|
maxHandleTextRect.position = new Vector3(0, -60, 0);
|
||||||
|
|
||||||
|
MinMaxSlider minMaxSlider = minMaxSliderRoot.AddComponent<MinMaxSlider>();
|
||||||
|
minMaxSlider.SliderBounds = sliderBoundsRect;
|
||||||
|
minMaxSlider.MinHandle = minHandleRect;
|
||||||
|
minMaxSlider.MaxHandle = maxHandleRect;
|
||||||
|
minMaxSlider.MiddleGraphic = middleGraphicRect;
|
||||||
|
minMaxSlider.MinText = minHandleTextComponent;
|
||||||
|
minMaxSlider.MaxText = maxHandleTextComponent;
|
||||||
|
|
||||||
|
Selection.activeGameObject = minMaxSliderRoot;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "UnityUIExtensions.editor",
|
"name": "UnityUIExtensions.editor",
|
||||||
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
|
"GUID:343deaaf83e0cee4ca978e7df0b80d21",
|
||||||
"GUID:2bafac87e7f4b9b418d9448d219b01ab",
|
"GUID:2bafac87e7f4b9b418d9448d219b01ab",
|
||||||
"GUID:cf414061cae3a954baf92763590f3127"
|
"GUID:cf414061cae3a954baf92763590f3127",
|
||||||
|
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
|
@ -14,5 +16,6 @@
|
||||||
"precompiledReferences": [],
|
"precompiledReferences": [],
|
||||||
"autoReferenced": true,
|
"autoReferenced": true,
|
||||||
"defineConstraints": [],
|
"defineConstraints": [],
|
||||||
"versionDefines": []
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
}
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d7bdc7e70331fe24aba2c9549f84c657
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -8,7 +8,7 @@ using UnityEngine.EventSystems;
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
[RequireComponent(typeof(RectTransform))]
|
[RequireComponent(typeof(RectTransform))]
|
||||||
[AddComponentMenu("UI/Extensions/BoxSlider")]
|
[AddComponentMenu("UI/Extensions/Sliders/BoxSlider")]
|
||||||
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
||||||
{
|
{
|
||||||
public enum Direction
|
public enum Direction
|
|
@ -0,0 +1,347 @@
|
||||||
|
///Credit brogan89
|
||||||
|
///Sourced from - https://github.com/brogan89/MinMaxSlider
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using TMPro;
|
||||||
|
using UnityEngine.Events;
|
||||||
|
using UnityEngine.EventSystems;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
[RequireComponent(typeof(RectTransform))]
|
||||||
|
[AddComponentMenu("UI/Extensions/Sliders/MinMax Slider")]
|
||||||
|
public class MinMaxSlider : Selectable, IBeginDragHandler, IDragHandler, IEndDragHandler
|
||||||
|
{
|
||||||
|
private enum DragState
|
||||||
|
{
|
||||||
|
Both,
|
||||||
|
Min,
|
||||||
|
Max
|
||||||
|
}
|
||||||
|
|
||||||
|
[Header("UI Controls")]
|
||||||
|
[SerializeField] private Camera customCamera = null;
|
||||||
|
[SerializeField] private RectTransform sliderBounds = null;
|
||||||
|
[SerializeField] private RectTransform minHandle = null;
|
||||||
|
[SerializeField] private RectTransform maxHandle = null;
|
||||||
|
[SerializeField] private RectTransform middleGraphic = null;
|
||||||
|
|
||||||
|
// text components (optional)
|
||||||
|
[Header("Display Text (Optional)")]
|
||||||
|
[SerializeField] private TextMeshProUGUI minText = null;
|
||||||
|
[SerializeField] private TextMeshProUGUI maxText = null;
|
||||||
|
[SerializeField] private string textFormat = "0";
|
||||||
|
|
||||||
|
// values
|
||||||
|
[Header("Limits")]
|
||||||
|
[SerializeField] private float minLimit = 0;
|
||||||
|
[SerializeField] private float maxLimit = 100;
|
||||||
|
|
||||||
|
[Header("Values")]
|
||||||
|
public bool wholeNumbers;
|
||||||
|
[SerializeField] private float minValue = 25;
|
||||||
|
[SerializeField] private float maxValue = 75;
|
||||||
|
|
||||||
|
public MinMaxValues Values => new MinMaxValues(minValue, maxValue, minLimit, maxLimit);
|
||||||
|
|
||||||
|
public RectTransform SliderBounds { get => sliderBounds; set => sliderBounds = value; }
|
||||||
|
public RectTransform MinHandle { get => minHandle; set => minHandle = value; }
|
||||||
|
public RectTransform MaxHandle { get => maxHandle; set => maxHandle = value; }
|
||||||
|
public RectTransform MiddleGraphic { get => middleGraphic; set => middleGraphic = value; }
|
||||||
|
public TextMeshProUGUI MinText { get => minText; set => minText = value; }
|
||||||
|
public TextMeshProUGUI MaxText { get => maxText; set => maxText = value; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Event invoked when either slider value has changed
|
||||||
|
/// <para></para>
|
||||||
|
/// T0 = min, T1 = max
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class SliderEvent : UnityEvent<float, float> { }
|
||||||
|
|
||||||
|
public SliderEvent onValueChanged = new SliderEvent();
|
||||||
|
|
||||||
|
private Vector2 dragStartPosition;
|
||||||
|
private float dragStartMinValue01;
|
||||||
|
private float dragStartMaxValue01;
|
||||||
|
private DragState dragState;
|
||||||
|
private bool passDragEvents; // this allows drag events to be passed through to scrollers
|
||||||
|
|
||||||
|
private Camera mainCamera;
|
||||||
|
private Canvas parentCanvas;
|
||||||
|
private bool isOverlayCanvas;
|
||||||
|
|
||||||
|
protected override void Start()
|
||||||
|
{
|
||||||
|
base.Start();
|
||||||
|
|
||||||
|
if (!sliderBounds)
|
||||||
|
{
|
||||||
|
sliderBounds = transform as RectTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
parentCanvas = GetComponentInParent<Canvas>();
|
||||||
|
isOverlayCanvas = parentCanvas.renderMode == RenderMode.ScreenSpaceOverlay;
|
||||||
|
mainCamera = customCamera != null ? customCamera : Camera.main;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetLimits(float minLimit, float maxLimit)
|
||||||
|
{
|
||||||
|
this.minLimit = wholeNumbers ? Mathf.RoundToInt(minLimit) : minLimit;
|
||||||
|
this.maxLimit = wholeNumbers ? Mathf.RoundToInt(maxLimit) : maxLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValues(MinMaxValues values, bool notify = true)
|
||||||
|
{
|
||||||
|
SetValues(values.minValue, values.maxValue, values.minLimit, values.maxLimit, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValues(float minValue, float maxValue, bool notify = true)
|
||||||
|
{
|
||||||
|
SetValues(minValue, maxValue, minLimit, maxLimit, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValues(float minValue, float maxValue, float minLimit, float maxLimit, bool notify = true)
|
||||||
|
{
|
||||||
|
this.minValue = wholeNumbers ? Mathf.RoundToInt(minValue) : minValue;
|
||||||
|
this.maxValue = wholeNumbers ? Mathf.RoundToInt(maxValue) : maxValue;
|
||||||
|
SetLimits(minLimit, maxLimit);
|
||||||
|
|
||||||
|
RefreshSliders();
|
||||||
|
UpdateText();
|
||||||
|
UpdateMiddleGraphic();
|
||||||
|
|
||||||
|
if (notify)
|
||||||
|
{
|
||||||
|
// event
|
||||||
|
onValueChanged.Invoke(this.minValue, this.maxValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshSliders()
|
||||||
|
{
|
||||||
|
SetSliderAnchors();
|
||||||
|
|
||||||
|
float clampedMin = Mathf.Clamp(minValue, minLimit, maxLimit);
|
||||||
|
SetMinHandleValue01(minHandle, GetPercentage(minLimit, maxLimit, clampedMin));
|
||||||
|
|
||||||
|
float clampedMax = Mathf.Clamp(maxValue, minLimit, maxLimit);
|
||||||
|
SetMaxHandleValue01(maxHandle, GetPercentage(minLimit, maxLimit, clampedMax));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetSliderAnchors()
|
||||||
|
{
|
||||||
|
minHandle.anchorMin = new Vector2(0, 0.5f);
|
||||||
|
minHandle.anchorMax = new Vector2(0, 0.5f);
|
||||||
|
minHandle.pivot = new Vector2(0.5f, 0.5f);
|
||||||
|
|
||||||
|
maxHandle.anchorMin = new Vector2(1, 0.5f);
|
||||||
|
maxHandle.anchorMax = new Vector2(1, 0.5f);
|
||||||
|
maxHandle.pivot = new Vector2(0.5f, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateText()
|
||||||
|
{
|
||||||
|
if (minText)
|
||||||
|
{
|
||||||
|
minText.SetText(minValue.ToString(textFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxText)
|
||||||
|
{
|
||||||
|
maxText.SetText(maxValue.ToString(textFormat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMiddleGraphic()
|
||||||
|
{
|
||||||
|
if (!middleGraphic) return;
|
||||||
|
|
||||||
|
middleGraphic.anchorMin = Vector2.zero;
|
||||||
|
middleGraphic.anchorMax = Vector2.one;
|
||||||
|
middleGraphic.offsetMin = new Vector2(minHandle.anchoredPosition.x, 0);
|
||||||
|
middleGraphic.offsetMax = new Vector2(maxHandle.anchoredPosition.x, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IDragHandler
|
||||||
|
public void OnBeginDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
passDragEvents = Math.Abs(eventData.delta.x) < Math.Abs(eventData.delta.y);
|
||||||
|
|
||||||
|
if (passDragEvents)
|
||||||
|
{
|
||||||
|
PassDragEvents<IBeginDragHandler>(x => x.OnBeginDrag(eventData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Camera uiCamera = isOverlayCanvas ? null : mainCamera;
|
||||||
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(sliderBounds, eventData.position, uiCamera, out dragStartPosition);
|
||||||
|
|
||||||
|
float dragStartValue = GetValueOfPointInSliderBounds01(dragStartPosition);
|
||||||
|
dragStartMinValue01 = GetMinHandleValue01(minHandle);
|
||||||
|
dragStartMaxValue01 = GetMaxHandleValue01(maxHandle);
|
||||||
|
|
||||||
|
// set drag state
|
||||||
|
if (dragStartValue < dragStartMinValue01 || RectTransformUtility.RectangleContainsScreenPoint(minHandle, eventData.position, uiCamera))
|
||||||
|
{
|
||||||
|
dragState = DragState.Min;
|
||||||
|
minHandle.SetAsLastSibling();
|
||||||
|
}
|
||||||
|
else if (dragStartValue > dragStartMaxValue01 || RectTransformUtility.RectangleContainsScreenPoint(maxHandle, eventData.position, uiCamera))
|
||||||
|
{
|
||||||
|
dragState = DragState.Max;
|
||||||
|
maxHandle.SetAsLastSibling();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dragState = DragState.Both;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (passDragEvents)
|
||||||
|
{
|
||||||
|
PassDragEvents<IDragHandler>(x => x.OnDrag(eventData));
|
||||||
|
}
|
||||||
|
else if (minHandle && maxHandle)
|
||||||
|
{
|
||||||
|
RectTransformUtility.ScreenPointToLocalPointInRectangle(sliderBounds, eventData.position, isOverlayCanvas ? null : mainCamera, out Vector2 clickPosition);
|
||||||
|
|
||||||
|
SetSliderAnchors();
|
||||||
|
|
||||||
|
if (dragState == DragState.Min || dragState == DragState.Max)
|
||||||
|
{
|
||||||
|
float dragPosition01 = GetValueOfPointInSliderBounds01(clickPosition);
|
||||||
|
float minHandleValue = GetMinHandleValue01(minHandle);
|
||||||
|
float maxHandleValue = GetMaxHandleValue01(maxHandle);
|
||||||
|
|
||||||
|
if (dragState == DragState.Min)
|
||||||
|
SetMinHandleValue01(minHandle, Mathf.Clamp(dragPosition01, 0, maxHandleValue));
|
||||||
|
else if (dragState == DragState.Max)
|
||||||
|
SetMaxHandleValue01(maxHandle, Mathf.Clamp(dragPosition01, minHandleValue, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float distancePercent = (clickPosition.x - dragStartPosition.x) / sliderBounds.rect.width;
|
||||||
|
SetMinHandleValue01(minHandle, dragStartMinValue01 + distancePercent);
|
||||||
|
SetMaxHandleValue01(maxHandle, dragStartMaxValue01 + distancePercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set values
|
||||||
|
float min = Mathf.Lerp(minLimit, maxLimit, GetMinHandleValue01(minHandle));
|
||||||
|
float max = Mathf.Lerp(minLimit, maxLimit, GetMaxHandleValue01(maxHandle));
|
||||||
|
SetValues(min, max);
|
||||||
|
|
||||||
|
UpdateText();
|
||||||
|
UpdateMiddleGraphic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnEndDrag(PointerEventData eventData)
|
||||||
|
{
|
||||||
|
if (passDragEvents)
|
||||||
|
{
|
||||||
|
PassDragEvents<IEndDragHandler>(x => x.OnEndDrag(eventData));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float minHandleValue = GetMinHandleValue01(minHandle);
|
||||||
|
float maxHandleValue = GetMaxHandleValue01(maxHandle);
|
||||||
|
|
||||||
|
// this safe guards a possible situation where the slides can get stuck
|
||||||
|
if (Math.Abs(minHandleValue) < MinMaxValues.FLOAT_TOL && Math.Abs(maxHandleValue) < MinMaxValues.FLOAT_TOL)
|
||||||
|
{
|
||||||
|
maxHandle.SetAsLastSibling();
|
||||||
|
}
|
||||||
|
else if (Math.Abs(minHandleValue - 1) < MinMaxValues.FLOAT_TOL && Math.Abs(maxHandleValue - 1) < MinMaxValues.FLOAT_TOL)
|
||||||
|
{
|
||||||
|
minHandle.SetAsLastSibling();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion IDragHandler
|
||||||
|
|
||||||
|
private void PassDragEvents<T>(Action<T> callback) where T : IEventSystemHandler
|
||||||
|
{
|
||||||
|
Transform parent = transform.parent;
|
||||||
|
|
||||||
|
while (parent != null)
|
||||||
|
{
|
||||||
|
foreach (var component in parent.GetComponents<Component>())
|
||||||
|
{
|
||||||
|
if (!(component is T)) continue;
|
||||||
|
|
||||||
|
callback.Invoke((T)(IEventSystemHandler)component);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = parent.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets position of max handle RectTransform
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle"></param>
|
||||||
|
/// <param name="value01">Normalized handle position</param>
|
||||||
|
private void SetMaxHandleValue01(RectTransform handle, float value01)
|
||||||
|
{
|
||||||
|
handle.anchoredPosition = new Vector2(value01 * sliderBounds.rect.width - sliderBounds.rect.width + sliderBounds.offsetMax.x, handle.anchoredPosition.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets position of min handle RectTransform
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle"></param>
|
||||||
|
/// <param name="value01">Normalized handle position</param>
|
||||||
|
private void SetMinHandleValue01(RectTransform handle, float value01)
|
||||||
|
{
|
||||||
|
handle.anchoredPosition = new Vector2(value01 * sliderBounds.rect.width + sliderBounds.offsetMin.x, handle.anchoredPosition.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns normalized position of max handle RectTransform
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle"></param>
|
||||||
|
/// <returns>Normalized position of max handle RectTransform</returns>
|
||||||
|
private float GetMaxHandleValue01(RectTransform handle)
|
||||||
|
{
|
||||||
|
return 1 + (handle.anchoredPosition.x - sliderBounds.offsetMax.x) / sliderBounds.rect.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns normalized position of min handle RectTransform
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle"></param>
|
||||||
|
/// <returns>Normalized position of min handle RectTransform</returns>
|
||||||
|
private float GetMinHandleValue01(RectTransform handle)
|
||||||
|
{
|
||||||
|
return (handle.anchoredPosition.x - sliderBounds.offsetMin.x) / sliderBounds.rect.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns normalized position of a point in a slider bounds rectangle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="position"></param>
|
||||||
|
/// <returns>Normalized position of a point in a slider bounds rectangle</returns>
|
||||||
|
private float GetValueOfPointInSliderBounds01(Vector2 position)
|
||||||
|
{
|
||||||
|
var width = sliderBounds.rect.width;
|
||||||
|
return Mathf.Clamp((position.x + width / 2) / width, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns percentage of input based on min and max values
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="min"></param>
|
||||||
|
/// <param name="max"></param>
|
||||||
|
/// <param name="input"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static float GetPercentage(float min, float max, float input)
|
||||||
|
{
|
||||||
|
return (input - min) / (max - min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b9f9954231c8bab419504a7ac5ff133e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -8,8 +8,8 @@ using UnityEngine.EventSystems;
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
[AddComponentMenu("UI/Extensions/Radial Slider")]
|
|
||||||
[RequireComponent(typeof(Image))]
|
[RequireComponent(typeof(Image))]
|
||||||
|
[AddComponentMenu("UI/Extensions/Sliders/Radial Slider")]
|
||||||
public class RadialSlider : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler
|
public class RadialSlider : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerUpHandler, IDragHandler
|
||||||
{
|
{
|
||||||
private bool isPointerDown, isPointerReleased, lerpInProgress;
|
private bool isPointerDown, isPointerReleased, lerpInProgress;
|
|
@ -9,9 +9,9 @@ using UnityEngine.EventSystems;
|
||||||
|
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
[AddComponentMenu("UI/Extensions/Range Slider", 34)]
|
|
||||||
[ExecuteInEditMode]
|
[ExecuteInEditMode]
|
||||||
[RequireComponent(typeof(RectTransform))]
|
[RequireComponent(typeof(RectTransform))]
|
||||||
|
[AddComponentMenu("UI/Extensions/Sliders/Range Slider", 34)]
|
||||||
public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
public class RangeSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
||||||
{
|
{
|
||||||
public enum Direction
|
public enum Direction
|
|
@ -9,8 +9,8 @@ using UnityEngine.EventSystems;
|
||||||
namespace UnityEngine.UI.Extensions
|
namespace UnityEngine.UI.Extensions
|
||||||
{
|
{
|
||||||
// Stepper control
|
// Stepper control
|
||||||
[AddComponentMenu("UI/Extensions/Stepper")]
|
|
||||||
[RequireComponent(typeof(RectTransform))]
|
[RequireComponent(typeof(RectTransform))]
|
||||||
|
[AddComponentMenu("UI/Extensions/Sliders/Stepper")]
|
||||||
public class Stepper : UIBehaviour
|
public class Stepper : UIBehaviour
|
||||||
{
|
{
|
||||||
private Selectable[] _sides;
|
private Selectable[] _sides;
|
|
@ -0,0 +1,50 @@
|
||||||
|
///Credit brogan89
|
||||||
|
///Sourced from - https://github.com/brogan89/MinMaxSlider
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace UnityEngine.UI.Extensions
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public struct MinMaxValues
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Floating point tolerance
|
||||||
|
/// </summary>
|
||||||
|
public const float FLOAT_TOL = 0.01f;
|
||||||
|
|
||||||
|
public float minValue, maxValue, minLimit, maxLimit;
|
||||||
|
public static MinMaxValues DEFUALT = new MinMaxValues(25, 75, 0, 100);
|
||||||
|
|
||||||
|
public MinMaxValues(float minValue, float maxValue, float minLimit, float maxLimit)
|
||||||
|
{
|
||||||
|
this.minValue = minValue;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
this.minLimit = minLimit;
|
||||||
|
this.maxLimit = maxLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor for when values equal limits
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="minValue"></param>
|
||||||
|
/// <param name="maxValue"></param>
|
||||||
|
public MinMaxValues(float minValue, float maxValue)
|
||||||
|
{
|
||||||
|
this.minValue = minValue;
|
||||||
|
this.maxValue = maxValue;
|
||||||
|
this.minLimit = minValue;
|
||||||
|
this.maxLimit = maxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAtMinAndMax()
|
||||||
|
{
|
||||||
|
return Math.Abs(minValue - minLimit) < FLOAT_TOL && Math.Abs(maxValue - maxLimit) < FLOAT_TOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"Values(min:{minValue}, max:{maxValue}) | Limits(min:{minLimit}, max:{maxLimit})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 44af036687d1cdb4da5686d3431d2c3c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Loading…
Reference in New Issue