278 lines
5.5 KiB
C#
278 lines
5.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.Events;
|
|
|
|
namespace UIWidgets
|
|
{
|
|
public abstract class CenteredSliderBase<T> : MonoBehaviour, IPointerClickHandler, IEventSystemHandler where T : struct
|
|
{
|
|
[Serializable]
|
|
public class OnChangeEvent : UnityEvent<T>
|
|
{
|
|
}
|
|
|
|
[SerializeField]
|
|
protected T _value;
|
|
|
|
[SerializeField]
|
|
protected T step;
|
|
|
|
[SerializeField]
|
|
protected T limitMin;
|
|
|
|
[SerializeField]
|
|
protected T limitMax;
|
|
|
|
[SerializeField]
|
|
protected RangeSliderHandle handle;
|
|
|
|
protected RectTransform handleRect;
|
|
|
|
[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 isInitCalled;
|
|
|
|
public T Value
|
|
{
|
|
get
|
|
{
|
|
return _value;
|
|
}
|
|
set
|
|
{
|
|
SetValue(value);
|
|
}
|
|
}
|
|
|
|
public T Step
|
|
{
|
|
get
|
|
{
|
|
return step;
|
|
}
|
|
set
|
|
{
|
|
step = value;
|
|
}
|
|
}
|
|
|
|
public T LimitMin
|
|
{
|
|
get
|
|
{
|
|
return limitMin;
|
|
}
|
|
set
|
|
{
|
|
limitMin = value;
|
|
SetValue(_value);
|
|
}
|
|
}
|
|
|
|
public T LimitMax
|
|
{
|
|
get
|
|
{
|
|
return limitMax;
|
|
}
|
|
set
|
|
{
|
|
limitMax = value;
|
|
SetValue(_value);
|
|
}
|
|
}
|
|
|
|
public RectTransform HandleRect
|
|
{
|
|
get
|
|
{
|
|
if (handle != null && handleRect == null)
|
|
{
|
|
handleRect = handle.transform as RectTransform;
|
|
}
|
|
return handleRect;
|
|
}
|
|
}
|
|
|
|
public RangeSliderHandle Handle
|
|
{
|
|
get
|
|
{
|
|
return handle;
|
|
}
|
|
set
|
|
{
|
|
SetHandle(value);
|
|
}
|
|
}
|
|
|
|
public RectTransform RangeSliderRect
|
|
{
|
|
get
|
|
{
|
|
if (rangeSliderRect == null)
|
|
{
|
|
rangeSliderRect = base.transform as RectTransform;
|
|
}
|
|
return rangeSliderRect;
|
|
}
|
|
}
|
|
|
|
protected virtual void Init()
|
|
{
|
|
if (!isInitCalled)
|
|
{
|
|
isInitCalled = true;
|
|
SetHandle(handle);
|
|
UpdateHandle();
|
|
UpdateFill();
|
|
}
|
|
}
|
|
|
|
protected virtual void SetValue(T value)
|
|
{
|
|
if (!EqualityComparer<T>.Default.Equals(_value, InBounds(value)))
|
|
{
|
|
_value = InBounds(value);
|
|
UpdateHandle();
|
|
OnValuesChange.Invoke(_value);
|
|
OnChange.Invoke();
|
|
}
|
|
}
|
|
|
|
protected virtual void SetHandle(RangeSliderHandle value)
|
|
{
|
|
handle = value;
|
|
handle.IsHorizontal = IsHorizontal;
|
|
handle.PositionLimits = PositionLimits;
|
|
handle.PositionChanged = UpdateValue;
|
|
handle.Increase = Increase;
|
|
handle.Decrease = Decrease;
|
|
}
|
|
|
|
protected virtual void Start()
|
|
{
|
|
Init();
|
|
}
|
|
|
|
public void SetLimit(T min, T max)
|
|
{
|
|
limitMin = min;
|
|
limitMax = max;
|
|
LimitMin = limitMin;
|
|
LimitMax = limitMax;
|
|
}
|
|
|
|
protected virtual bool IsHorizontal()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
protected float RangeSize()
|
|
{
|
|
return (!IsHorizontal()) ? UsableRangeRect.rect.height : UsableRangeRect.rect.width;
|
|
}
|
|
|
|
protected float HandleSize()
|
|
{
|
|
return (!IsHorizontal()) ? HandleRect.rect.height : HandleRect.rect.width;
|
|
}
|
|
|
|
protected void UpdateValue(float position)
|
|
{
|
|
_value = PositionToValue(position - GetStartPoint());
|
|
UpdateHandle();
|
|
OnValuesChange.Invoke(_value);
|
|
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 PositionLimits();
|
|
|
|
protected abstract T InBounds(T value);
|
|
|
|
protected abstract void Increase();
|
|
|
|
protected abstract void Decrease();
|
|
|
|
protected void UpdateHandle()
|
|
{
|
|
Vector2 anchoredPosition = HandleRect.anchoredPosition;
|
|
if (IsHorizontal())
|
|
{
|
|
anchoredPosition.x = ValueToPosition(_value) + HandleRect.rect.width * (HandleRect.pivot.x - 0.5f);
|
|
}
|
|
else
|
|
{
|
|
anchoredPosition.y = ValueToPosition(_value) + HandleRect.rect.width * (HandleRect.pivot.x - 0.5f);
|
|
}
|
|
HandleRect.anchoredPosition = anchoredPosition;
|
|
UpdateFill();
|
|
}
|
|
|
|
protected abstract bool IsPositiveValue();
|
|
|
|
protected virtual void UpdateFill()
|
|
{
|
|
FillRect.anchorMin = new Vector2(0.5f, 0.5f);
|
|
FillRect.anchorMax = new Vector2(0.5f, 0.5f);
|
|
if (IsHorizontal())
|
|
{
|
|
if (IsPositiveValue())
|
|
{
|
|
FillRect.pivot = new Vector2(0f, 0.5f);
|
|
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, HandleRect.localPosition.x - UsableRangeRect.localPosition.x);
|
|
}
|
|
else
|
|
{
|
|
FillRect.pivot = new Vector2(1f, 0.5f);
|
|
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, UsableRangeRect.localPosition.x - HandleRect.localPosition.x);
|
|
}
|
|
}
|
|
else if (IsPositiveValue())
|
|
{
|
|
FillRect.pivot = new Vector2(0.5f, 0f);
|
|
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, HandleRect.localPosition.y - UsableRangeRect.localPosition.y);
|
|
}
|
|
else
|
|
{
|
|
FillRect.pivot = new Vector2(0.5f, 1f);
|
|
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, UsableRangeRect.localPosition.y - HandleRect.localPosition.y);
|
|
}
|
|
}
|
|
|
|
public virtual void OnPointerClick(PointerEventData eventData)
|
|
{
|
|
Vector2 localPoint;
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(UsableRangeRect, eventData.position, eventData.pressEventCamera, out localPoint))
|
|
{
|
|
localPoint -= UsableRangeRect.rect.position;
|
|
float position = ((!IsHorizontal()) ? localPoint.y : localPoint.x) + GetStartPoint();
|
|
UpdateValue(position);
|
|
}
|
|
}
|
|
}
|
|
}
|