428 lines
9.0 KiB
C#
428 lines
9.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.Events;
|
|
|
|
namespace UIWidgets
|
|
{
|
|
public abstract class RangeSliderBase<T> : MonoBehaviour, IPointerClickHandler, IEventSystemHandler where T : struct
|
|
{
|
|
[Serializable]
|
|
public class OnChangeEvent : UnityEvent<T, T>
|
|
{
|
|
}
|
|
|
|
[SerializeField]
|
|
protected T valueMin;
|
|
|
|
[SerializeField]
|
|
protected T valueMax;
|
|
|
|
[SerializeField]
|
|
protected T step;
|
|
|
|
[SerializeField]
|
|
protected T limitMin;
|
|
|
|
[SerializeField]
|
|
protected T limitMax;
|
|
|
|
[SerializeField]
|
|
protected RangeSliderHandle handleMin;
|
|
|
|
protected RectTransform handleMinRect;
|
|
|
|
[SerializeField]
|
|
protected RangeSliderHandle handleMax;
|
|
|
|
protected RectTransform handleMaxRect;
|
|
|
|
[SerializeField]
|
|
protected RectTransform UsableRangeRect;
|
|
|
|
[SerializeField]
|
|
protected RectTransform FillRect;
|
|
|
|
protected RectTransform rangeSliderRect;
|
|
|
|
public OnChangeEvent OnValuesChange = new OnChangeEvent();
|
|
|
|
public UnityEvent OnChange = new UnityEvent();
|
|
|
|
public bool WholeNumberOfSteps;
|
|
|
|
private bool initCalled;
|
|
|
|
public T ValueMin
|
|
{
|
|
get
|
|
{
|
|
return valueMin;
|
|
}
|
|
set
|
|
{
|
|
if (!EqualityComparer<T>.Default.Equals(valueMin, InBoundsMin(value)))
|
|
{
|
|
valueMin = InBoundsMin(value);
|
|
UpdateMinHandle();
|
|
UpdateFill();
|
|
OnValuesChange.Invoke(valueMin, valueMax);
|
|
OnChange.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public T ValueMax
|
|
{
|
|
get
|
|
{
|
|
return valueMax;
|
|
}
|
|
set
|
|
{
|
|
if (!EqualityComparer<T>.Default.Equals(valueMax, InBoundsMax(value)))
|
|
{
|
|
valueMax = InBoundsMax(value);
|
|
UpdateMaxHandle();
|
|
UpdateFill();
|
|
OnValuesChange.Invoke(valueMin, valueMax);
|
|
OnChange.Invoke();
|
|
}
|
|
}
|
|
}
|
|
|
|
public T Step
|
|
{
|
|
get
|
|
{
|
|
return step;
|
|
}
|
|
set
|
|
{
|
|
step = value;
|
|
}
|
|
}
|
|
|
|
public T LimitMin
|
|
{
|
|
get
|
|
{
|
|
return limitMin;
|
|
}
|
|
set
|
|
{
|
|
limitMin = value;
|
|
ValueMin = valueMin;
|
|
ValueMax = valueMax;
|
|
}
|
|
}
|
|
|
|
public T LimitMax
|
|
{
|
|
get
|
|
{
|
|
return limitMax;
|
|
}
|
|
set
|
|
{
|
|
limitMax = value;
|
|
ValueMin = valueMin;
|
|
ValueMax = valueMax;
|
|
}
|
|
}
|
|
|
|
public RectTransform HandleMinRect
|
|
{
|
|
get
|
|
{
|
|
if (handleMin != null && handleMinRect == null)
|
|
{
|
|
handleMinRect = handleMin.transform as RectTransform;
|
|
}
|
|
return handleMinRect;
|
|
}
|
|
}
|
|
|
|
public RangeSliderHandle HandleMin
|
|
{
|
|
get
|
|
{
|
|
return handleMin;
|
|
}
|
|
set
|
|
{
|
|
handleMin = value;
|
|
handleMinRect = null;
|
|
handleMin.IsHorizontal = IsHorizontal;
|
|
handleMin.PositionLimits = MinPositionLimits;
|
|
handleMin.PositionChanged = UpdateMinValue;
|
|
handleMin.OnSubmit = SelectMaxHandle;
|
|
handleMin.Increase = IncreaseMin;
|
|
handleMin.Decrease = DecreaseMin;
|
|
HandleMinRect.anchorMin = new Vector2(0f, 0f);
|
|
HandleMinRect.anchorMax = ((!IsHorizontal()) ? new Vector2(1f, 0f) : new Vector2(0f, 1f));
|
|
}
|
|
}
|
|
|
|
public RectTransform HandleMaxRect
|
|
{
|
|
get
|
|
{
|
|
if (handleMax != null && handleMaxRect == null)
|
|
{
|
|
handleMaxRect = handleMax.transform as RectTransform;
|
|
}
|
|
return handleMaxRect;
|
|
}
|
|
}
|
|
|
|
public RangeSliderHandle HandleMax
|
|
{
|
|
get
|
|
{
|
|
return handleMax;
|
|
}
|
|
set
|
|
{
|
|
handleMax = value;
|
|
handleMaxRect = null;
|
|
handleMax.IsHorizontal = IsHorizontal;
|
|
handleMax.PositionLimits = MaxPositionLimits;
|
|
handleMax.PositionChanged = UpdateMaxValue;
|
|
handleMax.OnSubmit = SelectMinHandle;
|
|
handleMax.Increase = IncreaseMax;
|
|
handleMax.Decrease = DecreaseMax;
|
|
HandleMaxRect.anchorMin = new Vector2(0f, 0f);
|
|
HandleMaxRect.anchorMax = ((!IsHorizontal()) ? new Vector2(1f, 0f) : new Vector2(0f, 1f));
|
|
}
|
|
}
|
|
|
|
public RectTransform RangeSliderRect
|
|
{
|
|
get
|
|
{
|
|
if (rangeSliderRect == null)
|
|
{
|
|
rangeSliderRect = base.transform as RectTransform;
|
|
}
|
|
return rangeSliderRect;
|
|
}
|
|
}
|
|
|
|
private void Awake()
|
|
{
|
|
}
|
|
|
|
private void Init()
|
|
{
|
|
if (!initCalled)
|
|
{
|
|
initCalled = true;
|
|
HandleMin = handleMin;
|
|
HandleMax = handleMax;
|
|
UpdateMinHandle();
|
|
UpdateMaxHandle();
|
|
UpdateFill();
|
|
}
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
public void SetValue(T min, T max)
|
|
{
|
|
T x = valueMin;
|
|
T x2 = valueMax;
|
|
valueMin = min;
|
|
valueMax = max;
|
|
valueMin = InBoundsMin(valueMin);
|
|
valueMax = InBoundsMax(valueMax);
|
|
bool flag = EqualityComparer<T>.Default.Equals(x, valueMin);
|
|
bool flag2 = EqualityComparer<T>.Default.Equals(x2, valueMax);
|
|
if (!flag || !flag2)
|
|
{
|
|
UpdateMinHandle();
|
|
UpdateMaxHandle();
|
|
UpdateFill();
|
|
OnValuesChange.Invoke(valueMin, valueMax);
|
|
OnChange.Invoke();
|
|
}
|
|
}
|
|
|
|
public void SetLimit(T min, T max)
|
|
{
|
|
T x = valueMin;
|
|
T x2 = valueMax;
|
|
limitMin = min;
|
|
limitMax = max;
|
|
valueMin = InBoundsMin(valueMin);
|
|
valueMax = InBoundsMax(valueMax);
|
|
bool flag = EqualityComparer<T>.Default.Equals(x, valueMin);
|
|
bool flag2 = EqualityComparer<T>.Default.Equals(x2, valueMax);
|
|
if (!flag || !flag2)
|
|
{
|
|
UpdateMinHandle();
|
|
UpdateMaxHandle();
|
|
UpdateFill();
|
|
OnValuesChange.Invoke(valueMin, valueMax);
|
|
OnChange.Invoke();
|
|
}
|
|
}
|
|
|
|
protected virtual bool IsHorizontal()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected float FillSize()
|
|
{
|
|
return (!IsHorizontal()) ? UsableRangeRect.rect.height : UsableRangeRect.rect.width;
|
|
}
|
|
|
|
protected float MinHandleSize()
|
|
{
|
|
if (IsHorizontal())
|
|
{
|
|
return HandleMinRect.rect.width;
|
|
}
|
|
return HandleMinRect.rect.height;
|
|
}
|
|
|
|
protected float MaxHandleSize()
|
|
{
|
|
if (IsHorizontal())
|
|
{
|
|
return HandleMaxRect.rect.width;
|
|
}
|
|
return HandleMaxRect.rect.height;
|
|
}
|
|
|
|
protected void UpdateMinValue(float position)
|
|
{
|
|
valueMin = PositionToValue(position - GetStartPoint());
|
|
UpdateMinHandle();
|
|
UpdateFill();
|
|
OnValuesChange.Invoke(valueMin, valueMax);
|
|
OnChange.Invoke();
|
|
}
|
|
|
|
protected void UpdateMaxValue(float position)
|
|
{
|
|
valueMax = PositionToValue(position - GetStartPoint());
|
|
UpdateMaxHandle();
|
|
UpdateFill();
|
|
OnValuesChange.Invoke(valueMin, valueMax);
|
|
OnChange.Invoke();
|
|
}
|
|
|
|
protected abstract float ValueToPosition(T value);
|
|
|
|
protected abstract T PositionToValue(float position);
|
|
|
|
protected float GetStartPoint()
|
|
{
|
|
return (!IsHorizontal()) ? ((0f - UsableRangeRect.sizeDelta.y) / 2f) : ((0f - UsableRangeRect.sizeDelta.x) / 2f);
|
|
}
|
|
|
|
protected abstract Vector2 MinPositionLimits();
|
|
|
|
protected abstract Vector2 MaxPositionLimits();
|
|
|
|
protected abstract T InBounds(T value);
|
|
|
|
protected abstract T InBoundsMin(T value);
|
|
|
|
protected abstract T InBoundsMax(T value);
|
|
|
|
protected abstract void IncreaseMin();
|
|
|
|
protected abstract void DecreaseMin();
|
|
|
|
protected abstract void IncreaseMax();
|
|
|
|
protected abstract void DecreaseMax();
|
|
|
|
protected void UpdateMinHandle()
|
|
{
|
|
UpdateHandle(HandleMinRect, valueMin);
|
|
}
|
|
|
|
protected void UpdateMaxHandle()
|
|
{
|
|
UpdateHandle(HandleMaxRect, valueMax);
|
|
}
|
|
|
|
private void UpdateFill()
|
|
{
|
|
if (IsHorizontal())
|
|
{
|
|
FillRect.anchoredPosition = new Vector2(HandleMinRect.anchoredPosition.x, FillRect.anchoredPosition.y);
|
|
Vector2 sizeDelta = new Vector2(HandleMaxRect.anchoredPosition.x - HandleMinRect.anchoredPosition.x, FillRect.sizeDelta.y);
|
|
FillRect.sizeDelta = sizeDelta;
|
|
}
|
|
else
|
|
{
|
|
FillRect.anchoredPosition = new Vector2(FillRect.anchoredPosition.x, HandleMinRect.anchoredPosition.y);
|
|
Vector2 sizeDelta2 = new Vector2(FillRect.sizeDelta.x, HandleMaxRect.anchoredPosition.y - HandleMinRect.anchoredPosition.y);
|
|
FillRect.sizeDelta = sizeDelta2;
|
|
}
|
|
}
|
|
|
|
protected void UpdateHandle(RectTransform handleTransform, T value)
|
|
{
|
|
Vector2 anchoredPosition = handleTransform.anchoredPosition;
|
|
if (IsHorizontal())
|
|
{
|
|
anchoredPosition.x = ValueToPosition(value) + handleTransform.rect.width * (handleTransform.pivot.x - 0.5f);
|
|
}
|
|
else
|
|
{
|
|
anchoredPosition.y = ValueToPosition(value) + handleTransform.rect.height * (handleTransform.pivot.y - 0.5f);
|
|
}
|
|
handleTransform.anchoredPosition = anchoredPosition;
|
|
}
|
|
|
|
private void SelectMinHandle()
|
|
{
|
|
if (EventSystem.current != null && !EventSystem.current.alreadySelecting)
|
|
{
|
|
EventSystem.current.SetSelectedGameObject(handleMin.gameObject);
|
|
}
|
|
}
|
|
|
|
private void SelectMaxHandle()
|
|
{
|
|
if (EventSystem.current != null && !EventSystem.current.alreadySelecting)
|
|
{
|
|
EventSystem.current.SetSelectedGameObject(handleMax.gameObject);
|
|
}
|
|
}
|
|
|
|
public void OnPointerClick(PointerEventData eventData)
|
|
{
|
|
Vector2 localPoint;
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(UsableRangeRect, eventData.position, eventData.pressEventCamera, out localPoint))
|
|
{
|
|
localPoint -= UsableRangeRect.rect.position;
|
|
float num = ((!IsHorizontal()) ? localPoint.y : localPoint.x) + GetStartPoint();
|
|
float num2 = num - MaxHandleSize();
|
|
float num3 = ((!IsHorizontal()) ? HandleMinRect.anchoredPosition.y : HandleMinRect.anchoredPosition.x);
|
|
float num4 = ((!IsHorizontal()) ? HandleMaxRect.anchoredPosition.y : HandleMaxRect.anchoredPosition.x);
|
|
float num5 = num - num3;
|
|
float num6 = num4 - num2;
|
|
if (num5 < num6)
|
|
{
|
|
UpdateMinValue(num);
|
|
}
|
|
else
|
|
{
|
|
UpdateMaxValue(num2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|