using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; namespace UIWidgets { public abstract class CenteredSliderBase : MonoBehaviour, IPointerClickHandler, IEventSystemHandler where T : struct { [Serializable] public class OnChangeEvent : UnityEvent { } [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.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); } } } }