using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using System.Collections.Generic;
namespace UIWidgets {
///
/// Centered slider base class (zero at center, positive and negative parts have different scales).
///
public abstract class CenteredSliderBase : UIBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler
where T : struct
{
///
/// OnChangeEvent
///
[System.Serializable]
public class OnChangeEvent: UnityEvent {
}
///
/// Value.
///
[SerializeField]
protected T _value;
///
/// Gets or sets the value.
///
/// Value.
public T Value {
get {
return _value;
}
set {
SetValue(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;
SetValue(_value);
}
}
///
/// 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;
SetValue(_value);
}
}
///
/// The use value limits.
///
[SerializeField]
protected bool useValueLimits;
///
/// Gets or sets use value limits.
///
/// true if use value limits; otherwise, false.
public bool UseValueLimits {
get {
return useValueLimits;
}
set {
useValueLimits = value;
SetValue(_value);
}
}
///
/// The value minimum limit.
///
[SerializeField]
protected T valueMin;
///
/// Gets or sets the value minimum limit.
///
/// The value minimum limit.
public T ValueMin {
get {
return valueMin;
}
set {
valueMin = value;
SetValue(_value);
}
}
///
/// The value maximum limit.
///
[SerializeField]
protected T valueMax;
///
/// Gets or sets the value maximum limit.
///
/// The maximum limit.
public T ValueMax {
get {
return valueMax;
}
set {
valueMax = value;
SetValue(_value);
}
}
///
/// The step.
///
[SerializeField]
protected T step;
///
/// Gets or sets the step.
///
/// The step.
public T Step {
get {
return step;
}
set {
step = value;
}
}
///
/// Whole number of steps.
///
public bool WholeNumberOfSteps = false;
///
/// The handle.
///
[SerializeField]
protected RangeSliderHandle handle;
///
/// The handle rect.
///
protected RectTransform handleRect;
///
/// Gets the handle rect.
///
/// The handle rect.
public RectTransform HandleRect {
get {
if (handle!=null && handleRect==null)
{
handleRect = handle.transform as RectTransform;
}
return handleRect;
}
}
///
/// Gets or sets the handle.
///
/// The handle.
public RangeSliderHandle Handle {
get {
return handle;
}
set {
SetHandle(value);
}
}
///
/// 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();
///
/// Is init called?
///
bool isInitCalled;
///
/// Init this instance.
///
protected virtual void Init()
{
if (isInitCalled)
{
return ;
}
isInitCalled = true;
SetHandle(handle);
UpdateHandle();
UpdateFill();
}
///
/// Implementation of a callback that is sent if an associated RectTransform has it's dimensions changed.
///
protected override void OnRectTransformDimensionsChange()
{
UpdateHandle();
UpdateFill();
}
///
/// Called by a BaseInputModule when an OnPointerDown event occurs.
///
/// Event data.
public void OnPointerDown(PointerEventData eventData)
{
}
///
/// Called by a BaseInputModule when an OnPointerUp event occurs.
///
/// Event data.
public void OnPointerUp(PointerEventData eventData)
{
}
///
/// Sets the value.
///
/// Value.
protected virtual void SetValue(T value)
{
if (!EqualityComparer.Default.Equals(_value, InBounds(value)))
{
_value = InBounds(value);
UpdateHandle();
OnValuesChange.Invoke(_value);
OnChange.Invoke();
}
}
///
/// Sets the handle.
///
/// Value.
protected virtual void SetHandle(RangeSliderHandle value)
{
handle = value;
handle.IsHorizontal = IsHorizontal;
handle.PositionLimits = PositionLimits;
handle.PositionChanged = UpdateValue;
handle.Increase = Increase;
handle.Decrease = Decrease;
}
///
/// Start this instance.
///
protected override void Start()
{
Init();
}
///
/// Sets the limits.
///
/// Minimum.
/// Max.
public void SetLimit(T min, T max)
{
// set limits to skip InBounds check
limitMin = min;
limitMax = max;
// set limits with InBounds check and update handle's positions
LimitMin = limitMin;
LimitMax = limitMax;
}
///
/// Sets the value limits.
///
/// Minimum.
/// Max.
public void SetValueLimit(T min, T max)
{
// set limits to skip InBounds check
valueMin = min;
valueMax = max;
// set limits with InBounds check and update handle's positions
ValueMin = valueMin;
ValueMax = valueMax;
}
///
/// 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 RangeSize()
{
return (IsHorizontal()) ? UsableRangeRect.rect.width : UsableRangeRect.rect.height;
}
///
/// Size of the handle.
///
/// The handle size.
protected float HandleSize()
{
return (IsHorizontal()) ? HandleRect.rect.width : HandleRect.rect.height;
}
///
/// Updates the minimum value.
///
/// Position.
protected void UpdateValue(float position)
{
_value = PositionToValue(position - GetStartPoint());
UpdateHandle();
OnValuesChange.Invoke(_value);
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 PositionLimits();
///
/// Fit value to bounds.
///
/// Value.
/// Value.
protected abstract T InBounds(T value);
///
/// Increases the minimum value.
///
protected abstract void Increase();
///
/// Decreases the minimum value.
///
protected abstract void Decrease();
///
/// Updates the handle.
///
protected void UpdateHandle()
{
var new_position = HandleRect.anchoredPosition;
if (IsHorizontal())
{
new_position.x = ValueToPosition(_value) + HandleRect.rect.width * (HandleRect.pivot.x - 0.5f);
}
else
{
new_position.y = ValueToPosition(_value) + HandleRect.rect.width * (HandleRect.pivot.x - 0.5f);
}
HandleRect.anchoredPosition = new_position;
UpdateFill();
}
///
/// Determines whether this instance is positive value.
///
/// true if this instance is positive value; otherwise, false.
protected abstract bool IsPositiveValue();
///
/// Updates the fill size.
///
protected virtual void UpdateFill()
{
FillRect.anchorMin = new Vector2(0.5f, 0.5f);
FillRect.anchorMax = new Vector2(0.5f, 0.5f);//1.0
if (IsHorizontal())
{
if (IsPositiveValue())
{
FillRect.pivot = new Vector2(0.0f, 0.5f);
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, HandleRect.localPosition.x - UsableRangeRect.localPosition.x);
}
else
{
FillRect.pivot = new Vector2(1.0f, 0.5f);
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, UsableRangeRect.localPosition.x - HandleRect.localPosition.x);
}
}
else
{
if (IsPositiveValue())
{
FillRect.pivot = new Vector2(0.5f, 0.0f);
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, HandleRect.localPosition.y - UsableRangeRect.localPosition.y);
}
else
{
FillRect.pivot = new Vector2(0.5f, 1.0f);
FillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, UsableRangeRect.localPosition.y - HandleRect.localPosition.y);
}
}
}
///
/// Raises the pointer click event.
///
/// Event data.
public virtual 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_position = (IsHorizontal() ? curCursor.x : curCursor.y) + GetStartPoint();
UpdateValue(new_position);
}
#if UNITY_EDITOR
///
/// Handle values change from editor.
///
public void EditorUpdate()
{
if (handle!=null && UsableRangeRect!=null && FillRect!=null)
{
UpdateHandle();
}
}
#endif
}
}