using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using System.Collections.Generic;
namespace UIWidgets {
///
/// Range slider base.
///
public abstract class RangeSliderBase : MonoBehaviour, IPointerClickHandler
where T : struct
{
///
/// OnChangeEvent.
///
[System.Serializable]
public class OnChangeEvent : UnityEvent {
}
///
/// The minimum value.
///
[SerializeField]
protected T valueMin;
///
/// Gets or sets the minimum value.
///
/// The minimum value.
public T ValueMin {
get {
return valueMin;
}
set {
if (!EqualityComparer.Default.Equals(valueMin, InBoundsMin(value)))
{
valueMin = InBoundsMin(value);
UpdateMinHandle();
UpdateFill();
OnValuesChange.Invoke(valueMin, valueMax);
OnChange.Invoke();
}
}
}
///
/// The maximum value.
///
[SerializeField]
protected T valueMax;
///
/// Gets or sets the maximum value.
///
/// The maximum value.
public T ValueMax {
get {
return valueMax;
}
set {
if (!EqualityComparer.Default.Equals(valueMax, InBoundsMax(value)))
{
valueMax = InBoundsMax(value);
UpdateMaxHandle();
UpdateFill();
OnValuesChange.Invoke(valueMin, valueMax);
OnChange.Invoke();
}
}
}
///
/// The step.
///
[SerializeField]
protected T step;
///
/// Gets or sets the step.
///
/// The step.
public T Step {
get {
return step;
}
set {
step = value;
}
}
///
/// The minimum limit.
///
[SerializeField]
protected T limitMin;
///
/// Gets or sets the minimum limit.
///
/// The minimum limit.
public T LimitMin {
get {
return limitMin;
}
set {
limitMin = value;
ValueMin = valueMin;
ValueMax = valueMax;
}
}
///
/// The maximum limit.
///
[SerializeField]
protected T limitMax;
///
/// Gets or sets the maximum limit.
///
/// The maximum limit.
public T LimitMax {
get {
return limitMax;
}
set {
limitMax = value;
ValueMin = valueMin;
ValueMax = valueMax;
}
}
///
/// The handle minimum.
///
[SerializeField]
protected RangeSliderHandle handleMin;
///
/// The handle minimum rect.
///
protected RectTransform handleMinRect;
///
/// Gets the handle minimum rect.
///
/// The handle minimum rect.
public RectTransform HandleMinRect {
get {
if (handleMin!=null && handleMinRect==null)
{
handleMinRect = handleMin.transform as RectTransform;
}
return handleMinRect;
}
}
///
/// Gets or sets the handle minimum.
///
/// The handle minimum.
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(0, 0);
HandleMinRect.anchorMax = (IsHorizontal()) ? new Vector2(0, 1) : new Vector2(1, 0);
}
}
///
/// The handle max.
///
[SerializeField]
protected RangeSliderHandle handleMax;
///
/// The handle max rect.
///
protected RectTransform handleMaxRect;
///
/// Gets the handle maximum rect.
///
/// The handle maximum rect.
public RectTransform HandleMaxRect {
get {
if (handleMax!=null && handleMaxRect==null)
{
handleMaxRect = handleMax.transform as RectTransform;
}
return handleMaxRect;
}
}
///
/// Gets or sets the handle max.
///
/// The handle max.
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(0, 0);
HandleMaxRect.anchorMax = (IsHorizontal()) ? new Vector2(0, 1) : new Vector2(1, 0);
}
}
///
/// The usable range rect.
///
[SerializeField]
protected RectTransform UsableRangeRect;
///
/// The fill rect.
///
[SerializeField]
protected RectTransform FillRect;
///
/// The range slider rect.
///
protected RectTransform rangeSliderRect;
///
/// Gets the handle maximum rect.
///
/// The handle maximum rect.
public RectTransform RangeSliderRect {
get {
if (rangeSliderRect==null)
{
rangeSliderRect = transform as RectTransform;
}
return rangeSliderRect;
}
}
///
/// OnValuesChange event.
///
public OnChangeEvent OnValuesChange = new OnChangeEvent();
///
/// OnChange event.
///
public UnityEvent OnChange = new UnityEvent();
///
/// Whole number of steps.
///
public bool WholeNumberOfSteps = false;
void Awake()
{
}
bool initCalled;
void Init()
{
if (initCalled)
{
return ;
}
initCalled = true;
HandleMin = handleMin;
HandleMax = handleMax;
UpdateMinHandle();
UpdateMaxHandle();
UpdateFill();
}
void Start()
{
Init();
}
///
/// Sets the values.
///
/// Minimum.
/// Max.
public void SetValue(T min, T max)
{
var oldValueMin = valueMin;
var oldValueMax = valueMax;
valueMin = min;
valueMax = max;
valueMin = InBoundsMin(valueMin);
valueMax = InBoundsMax(valueMax);
var min_equals = EqualityComparer.Default.Equals(oldValueMin, valueMin);
var max_equals = EqualityComparer.Default.Equals(oldValueMax, valueMax);
if (!min_equals || !max_equals)
{
UpdateMinHandle();
UpdateMaxHandle();
UpdateFill();
OnValuesChange.Invoke(valueMin, valueMax);
OnChange.Invoke();
}
}
///
/// Sets the limits.
///
/// Minimum.
/// Max.
public void SetLimit(T min, T max)
{
var oldValueMin = valueMin;
var oldValueMax = valueMax;
limitMin = min;
limitMax = max;
valueMin = InBoundsMin(valueMin);
valueMax = InBoundsMax(valueMax);
var min_equals = EqualityComparer.Default.Equals(oldValueMin, valueMin);
var max_equals = EqualityComparer.Default.Equals(oldValueMax, valueMax);
if (!min_equals || !max_equals)
{
UpdateMinHandle();
UpdateMaxHandle();
UpdateFill();
OnValuesChange.Invoke(valueMin, valueMax);
OnChange.Invoke();
}
}
///
/// Determines whether this instance is horizontal.
///
/// true if this instance is horizontal; otherwise, false.
protected virtual bool IsHorizontal()
{
return true;
}
///
/// Returns size of usable rect.
///
/// The size.
protected float FillSize()
{
return (IsHorizontal()) ? UsableRangeRect.rect.width : UsableRangeRect.rect.height;
}
///
/// Minimum size of the handle.
///
/// The handle size.
protected float MinHandleSize()
{
if (IsHorizontal())
{
return HandleMinRect.rect.width;
}
else
{
return HandleMinRect.rect.height;
}
}
///
/// Maximum size of the handle.
///
/// The handle size.
protected float MaxHandleSize()
{
if (IsHorizontal())
{
return HandleMaxRect.rect.width;
}
else
{
return HandleMaxRect.rect.height;
}
}
///
/// Updates the minimum value.
///
/// Position.
protected void UpdateMinValue(float position)
{
valueMin = PositionToValue(position - GetStartPoint());
UpdateMinHandle();
UpdateFill();
OnValuesChange.Invoke(valueMin, valueMax);
OnChange.Invoke();
}
///
/// Updates the maximum value.
///
/// Position.
protected void UpdateMaxValue(float position)
{
valueMax = PositionToValue(position - GetStartPoint());
UpdateMaxHandle();
UpdateFill();
OnValuesChange.Invoke(valueMin, valueMax);
OnChange.Invoke();
}
///
/// Value to position.
///
/// Position.
/// Value.
protected abstract float ValueToPosition(T value);
///
/// Position to value.
///
/// Value.
/// Position.
protected abstract T PositionToValue(float position);
///
/// Gets the start point.
///
/// The start point.
protected float GetStartPoint()
{
return IsHorizontal() ? -UsableRangeRect.sizeDelta.x / 2f : -UsableRangeRect.sizeDelta.y / 2f;
}
///
/// Position range for minimum handle.
///
/// The position limits.
protected abstract Vector2 MinPositionLimits();
///
/// Position range for maximum handle.
///
/// The position limits.
protected abstract Vector2 MaxPositionLimits();
///
/// Fit value to bounds.
///
/// Value.
/// Value.
protected abstract T InBounds(T value);
///
/// Fit minumum value to bounds.
///
/// Value.
/// Value.
protected abstract T InBoundsMin(T value);
///
/// Fit maximum value to bounds.
///
/// Value.
/// Value.
protected abstract T InBoundsMax(T value);
///
/// Increases the minimum value.
///
protected abstract void IncreaseMin();
///
/// Decreases the minimum value.
///
protected abstract void DecreaseMin();
///
/// Increases the maximum value.
///
protected abstract void IncreaseMax();
///
/// Decreases the maximum value.
///
protected abstract void DecreaseMax();
///
/// Updates the minimum handle.
///
protected void UpdateMinHandle()
{
UpdateHandle(HandleMinRect, valueMin);
}
///
/// Updates the maximum handle.
///
protected void UpdateMaxHandle()
{
UpdateHandle(HandleMaxRect, valueMax);
}
///
/// Updates the fill.
///
void UpdateFill()
{
if (IsHorizontal())
{
FillRect.anchoredPosition = new Vector2(HandleMinRect.anchoredPosition.x, FillRect.anchoredPosition.y);
var 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);
var sizeDelta = new Vector2(FillRect.sizeDelta.x, (+ HandleMaxRect.anchoredPosition.y - HandleMinRect.anchoredPosition.y));
FillRect.sizeDelta = sizeDelta;
}
}
///
/// Updates the handle.
///
/// Handle transform.
/// Value.
protected void UpdateHandle(RectTransform handleTransform, T value)
{
var new_position = handleTransform.anchoredPosition;
if (IsHorizontal())
{
new_position.x = ValueToPosition(value) + handleTransform.rect.width * (handleTransform.pivot.x - 0.5f);
}
else
{
new_position.y = ValueToPosition(value) + handleTransform.rect.height * (handleTransform.pivot.y - 0.5f);
}
handleTransform.anchoredPosition = new_position;
}
///
/// Selects the minimum handle.
///
void SelectMinHandle()
{
if ((EventSystem.current!=null) && (!EventSystem.current.alreadySelecting))
{
EventSystem.current.SetSelectedGameObject(handleMin.gameObject);
}
}
///
/// Selects the max handle.
///
void SelectMaxHandle()
{
if ((EventSystem.current!=null) && (!EventSystem.current.alreadySelecting))
{
EventSystem.current.SetSelectedGameObject(handleMax.gameObject);
}
}
///
/// Raises the pointer click event.
///
/// Event data.
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.button!=PointerEventData.InputButton.Left)
{
return;
}
Vector2 curCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(UsableRangeRect, eventData.position, eventData.pressEventCamera, out curCursor))
{
return ;
}
curCursor -= UsableRangeRect.rect.position;
var new_min_position = (IsHorizontal() ? curCursor.x : curCursor.y) + GetStartPoint();
var new_max_position = new_min_position - MaxHandleSize();
var min_position = IsHorizontal() ? HandleMinRect.anchoredPosition.x : HandleMinRect.anchoredPosition.y;
var max_position = IsHorizontal() ? HandleMaxRect.anchoredPosition.x : HandleMaxRect.anchoredPosition.y;
var delta_min = new_min_position - min_position;
var delta_max = max_position - new_max_position;
if (delta_min < delta_max)
{
UpdateMinValue(new_min_position);
}
else
{
UpdateMaxValue(new_max_position);
}
}
#if UNITY_EDITOR
///
/// Handle values change from editor.
///
public void EditorUpdate()
{
if (handleMin!=null && handleMax!=null && UsableRangeRect!=null && FillRect!=null)
{
UpdateMinHandle();
UpdateMaxHandle();
UpdateFill();
}
}
#endif
}
}