Files
2026-02-21 16:45:37 +08:00

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);
}
}
}
}