OldBlueWater/BlueWater/Assets/Doozy/Runtime/UIManager/Components/UISlider.cs

921 lines
34 KiB
C#

// Copyright (c) 2015 - 2023 Doozy Entertainment. All Rights Reserved.
// This code can only be used under the standard Unity Asset Store End User License Agreement
// A Copy of the EULA APPENDIX 1 is available at http://unity3d.com/company/legal/as_terms
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Doozy.Runtime.Common.Attributes;
using Doozy.Runtime.Common.Events;
using Doozy.Runtime.Common.Extensions;
using Doozy.Runtime.Common.Utils;
using Doozy.Runtime.Mody;
using Doozy.Runtime.Reactor;
using Doozy.Runtime.Signals;
using Doozy.Runtime.UIManager.Utils;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using MoveDirection = UnityEngine.EventSystems.MoveDirection;
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
namespace Doozy.Runtime.UIManager.Components
{
/// <summary>
/// Slider component based on UISelectable with category/name id identifier.
/// </summary>
[RequireComponent(typeof(RectTransform))]
[AddComponentMenu("Doozy/UI/Components/UISlider")]
[SelectionBase]
public partial class UISlider : UISelectable, IDragHandler, IInitializePotentialDragHandler
{
private const float TOLERANCE = 0.0001f;
#if UNITY_EDITOR
[UnityEditor.MenuItem("GameObject/Doozy/UI/Components/UISlider", false, 8)]
private static void CreateComponent(UnityEditor.MenuCommand menuCommand)
{
GameObjectUtils.AddToScene<UISlider>("UISlider", false, true);
}
#endif
/// <summary> UISliders database </summary>
public static HashSet<UISlider> database { get; private set; } = new HashSet<UISlider>();
[ExecuteOnReload]
// ReSharper disable once UnusedMember.Local
private static void OnReload()
{
database = new HashSet<UISlider>();
}
[ClearOnReload]
private static SignalStream s_stream;
/// <summary> UISlider signal stream </summary>
public static SignalStream stream => s_stream ?? (s_stream = SignalsService.GetStream(k_StreamCategory, nameof(UISlider)));
/// <summary> All sliders that are active and enabled </summary>
public static IEnumerable<UISlider> availableSliders => database.Where(item => item.isActiveAndEnabled);
/// <summary> TRUE is this selectable is selected by EventSystem.current, FALSE otherwise </summary>
public bool isSelected => EventSystem.current.currentSelectedGameObject == gameObject;
/// <summary> Type of selectable </summary>
public override SelectableType selectableType => SelectableType.Button;
/// <summary> UISlider identifier </summary>
public UISliderId Id;
/// <summary> Slider changed its value - executed when the slider changes its value </summary>
[Obsolete("Use OnValueChanged instead")]
public FloatEvent OnValueChangedCallback;
/// <summary>
/// Fired when the value changed.
/// Returns the new value.
/// </summary>
public FloatEvent OnValueChanged = new FloatEvent();
/// <summary>
/// Fired when the value increases.
/// Returns the difference between the new value and the previous value.
/// <para/> Example: if the previous value was 0.5 and the new value is 0.7, the difference is 0.2
/// </summary>
public FloatEvent OnValueIncremented = new FloatEvent();
/// <summary>
/// Fired when the value decreases.
/// Returns the difference between the new value and the previous value.
/// <para/> Example: if the previous value was 10 and the new value is 5, the returned value will be -5
/// </summary>
public FloatEvent OnValueDecremented = new FloatEvent();
/// <summary> Fired when the value was reset </summary>
public ModyEvent OnValueReset = new ModyEvent();
/// <summary> Fired when the value has reached the minimum value </summary>
public ModyEvent OnValueReachedMin = new ModyEvent();
/// <summary> Fired when the value has reached the maximum value </summary>
public ModyEvent OnValueReachedMax = new ModyEvent();
[SerializeField] private RectTransform FillRect;
/// <summary> Optional RectTransform to use as fill for the slider </summary>
public RectTransform fillRect
{
get => FillRect;
set
{
if (value == FillRect)
return;
FillRect = value;
UpdateCachedReferences();
UpdateVisuals();
}
}
[SerializeField] private RectTransform HandleRect;
/// <summary> Optional RectTransform to use as a handle for the slider </summary>
public RectTransform handleRect
{
get => HandleRect;
set
{
if (value == HandleRect)
return;
HandleRect = value;
UpdateCachedReferences();
UpdateVisuals();
}
}
[SerializeField] private SlideDirection Direction = SlideDirection.LeftToRight;
/// <summary> The direction of the slider, from minimum to maximum value </summary>
public SlideDirection direction
{
get => Direction;
set
{
Direction = value;
UpdateVisuals();
}
}
[SerializeField] private float MinValue;
/// <summary> The minimum allowed value of the slider </summary>
public float minValue
{
get => MinValue;
set
{
MinValue = value;
Value.Clamp(MinValue, MaxValue);
UpdateLabel(minValueLabel, MinValue);
UpdateVisuals();
}
}
[SerializeField] private float MaxValue = 1f;
/// <summary> The maximum allowed value of the slider </summary>
public float maxValue
{
get => MaxValue;
set
{
MaxValue = value;
Value.Clamp(MinValue, MaxValue);
UpdateLabel(maxValueLabel, MaxValue);
UpdateVisuals();
}
}
[SerializeField] private bool WholeNumbers;
/// <summary> Should the value only be allowed to be whole numbers? </summary>
public bool wholeNumbers
{
get => WholeNumbers;
set
{
WholeNumbers = value;
if (!value)
return;
MinValue = Mathf.Round(MinValue);
MaxValue = Mathf.Round(MaxValue);
Value.Clamp(MinValue, MaxValue);
UpdateVisuals();
UpdateLabel(minValueLabel, MinValue);
UpdateLabel(maxValueLabel, MaxValue);
UpdateLabel(valueLabel, Value);
}
}
[SerializeField] protected float Value;
/// <summary> The current value of the slider </summary>
public virtual float value
{
get => wholeNumbers ? Mathf.Round(Value) : Value;
set => SetValue(value);
}
[SerializeField] private float DefaultValue;
/// <summary> Reset value for the slider </summary>
public float defaultValue
{
get => DefaultValue;
set => DefaultValue = Mathf.Clamp(value, minValue, maxValue);
}
[SerializeField] private TMP_Text ValueLabel;
/// <summary> Reference to the value label that displays the current value of the slider </summary>
public TMP_Text valueLabel
{
get => ValueLabel;
private set
{
ValueLabel = value;
UpdateLabel(ValueLabel, Value);
}
}
[SerializeField] private TMP_Text MinValueLabel;
/// <summary> Reference to the value label that displays the min value of the slider </summary>
public TMP_Text minValueLabel
{
get => MinValueLabel;
private set
{
MinValueLabel = value;
UpdateLabel(MinValueLabel, minValue);
}
}
[SerializeField] private TMP_Text MaxValueLabel;
/// <summary> Reference to the value label that displays the max value of the slider </summary>
public TMP_Text maxValueLabel
{
get => MaxValueLabel;
private set
{
MaxValueLabel = value;
UpdateLabel(MaxValueLabel, maxValue);
}
}
[SerializeField] private Progressor TargetProgressor;
/// <summary> Reference to a Progressor that will be updated when the slider value changes </summary>
public Progressor targetProgressor
{
get => TargetProgressor;
private set
{
TargetProgressor = value;
if (value == null) return;
UpdateTargetProgressorMinMax();
UpdateTargetProgressorValue();
}
}
/// <summary>
/// When true, the slider will update the target progressor value with SetValueAt instead of PlayToValue.
/// Basically, if true, the progressor will not animate when the slider value changes.
/// </summary>
public bool InstantProgressorUpdate = true;
/// <summary> Reset the slider value to the default value OnEnable </summary>
public bool ResetValueOnEnable = false;
/// <summary> The current value of the slider normalized into a value between 0 and 1 </summary>
public float normalizedValue
{
get => Mathf.Approximately(minValue, maxValue) ? 0 : Mathf.InverseLerp(minValue, maxValue, value);
set => this.value = Mathf.Lerp(minValue, maxValue, value);
}
private Axis axis => GetAxis(direction);
private static Axis GetAxis(SlideDirection slideDirection)
{
switch (slideDirection)
{
case SlideDirection.LeftToRight:
case SlideDirection.RightToLeft:
return Axis.Horizontal;
case SlideDirection.BottomToTop:
case SlideDirection.TopToBottom:
return Axis.Vertical;
default:
throw new ArgumentOutOfRangeException();
}
}
private bool reverseValue => Direction == SlideDirection.RightToLeft || Direction == SlideDirection.TopToBottom;
private Image m_FillImage;
private Transform m_FillTransform;
private RectTransform m_FillContainerRect;
private Transform m_HandleTransform;
private RectTransform m_HandleContainerRect;
// The offset from handle position to mouse down position
private Vector2 m_Offset = Vector2.zero;
private DrivenRectTransformTracker m_Tracker;
// This "delayed" mechanism is required for case 1037681.
private bool m_DelayedUpdateVisuals;
// Size of each step.
private float stepSize => wholeNumbers ? 1 : (maxValue - minValue) * 0.1f;
private UISlider()
{
Id = new UISliderId();
}
#if UNITY_EDITOR
protected override void OnValidate()
{
MinValue = WholeNumbers ? MinValue.Round(0) : MinValue;
MaxValue = WholeNumbers ? MaxValue.Round(0) : MaxValue;
Value = WholeNumbers ? Value.Round(0) : Value;
if (IsActive())
{
UpdateCachedReferences();
m_DelayedUpdateVisuals = true;
}
base.OnValidate();
}
#endif //UNITY_EDITOR
public override void Rebuild(CanvasUpdate executing)
{
base.Rebuild(executing);
#if UNITY_EDITOR
if (executing == CanvasUpdate.Prelayout)
{
#pragma warning disable CS0618
OnValueChangedCallback?.Invoke(value);
#pragma warning restore CS0618
OnValueChanged?.Invoke(value);
}
#endif //UNITY_EDITOR
}
protected override void Awake()
{
database.Add(this);
base.Awake();
// OnValueChanged.AddListener(v => Debug.Log($"Slider {Id} value changed to {v}"));
// OnValueIncremented.AddListener(v => Debug.Log($"Slider {Id} value incremented to {v}"));
// OnValueDecremented.AddListener(v => Debug.Log($"Slider {Id} value decremented to {v}"));
// OnValueReset.Event.AddListener(() => Debug.Log($"Slider {Id} value reset to {defaultValue}"));
// OnValueReachedMin.Event.AddListener(() => Debug.Log($"Slider {Id} value reached min value {minValue}"));
// OnValueReachedMax.Event.AddListener(() => Debug.Log($"Slider {Id} value reached max value {maxValue}"));
}
protected override void OnEnable()
{
database.Remove(null);
base.OnEnable();
if (!Application.isPlaying) return;
UpdateCachedReferences();
UpdateTargetProgressorMinMax();
if (ResetValueOnEnable)
{
ResetValue();
}
else
{
UpdateTargetProgressorValue();
}
UpdateVisuals();
UpdateLabel(minValueLabel, minValue);
UpdateLabel(maxValueLabel, maxValue);
}
protected override void OnDisable()
{
database.Remove(null);
m_Tracker.Clear();
UpdateTargetProgressorValue();
base.OnDisable();
}
protected override void OnDestroy()
{
database.Remove(null);
database.Remove(this);
base.OnDestroy();
}
private void Update()
{
if (!m_DelayedUpdateVisuals) return;
m_DelayedUpdateVisuals = false;
SetValue(Value, false);
UpdateVisuals();
}
protected override void OnDidApplyAnimationProperties()
{
// Has value changed? Various elements of the slider have the old normalisedValue assigned, we can use this to perform a comparison.
// We also need to ensure the value stays within min/max.
Value = ClampValue(Value);
float previousNormalizedValue = normalizedValue;
if (m_FillContainerRect != null)
{
if (m_FillImage != null && m_FillImage.type == Image.Type.Filled)
{
previousNormalizedValue = m_FillImage.fillAmount;
}
else
{
previousNormalizedValue =
reverseValue
? 1 - FillRect.anchorMin[(int)axis]
: FillRect.anchorMax[(int)axis];
}
}
else if (m_HandleContainerRect != null)
{
previousNormalizedValue =
reverseValue
? 1 - HandleRect.anchorMin[(int)axis]
: HandleRect.anchorMin[(int)axis];
}
UpdateVisuals();
if (Mathf.Approximately(previousNormalizedValue, normalizedValue))
return;
UISystemProfilerApi.AddMarker("Slider.value", this);
#pragma warning disable CS0618
OnValueChangedCallback.Invoke(Value);
#pragma warning restore CS0618
OnValueChanged.Invoke(Value);
}
private void UpdateCachedReferences()
{
if (FillRect && FillRect != (RectTransform)transform)
{
m_FillTransform = FillRect.transform;
m_FillImage = FillRect.GetComponent<Image>();
if (m_FillTransform.parent != null)
m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>();
}
else
{
FillRect = null;
m_FillContainerRect = null;
m_FillImage = null;
}
if (HandleRect && HandleRect != (RectTransform)transform)
{
m_HandleTransform = HandleRect.transform;
if (m_HandleTransform.parent != null)
m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
}
else
{
HandleRect = null;
m_HandleContainerRect = null;
}
}
/// <summary> Reset the current int or float value, depending on the stepper's value type, to the default value. </summary>
public void ResetValue()
{
SetValue(defaultValue);
OnValueReset.Execute();
}
private float ClampValue(float input) =>
wholeNumbers
? input.Clamp(minValue, maxValue).Round(0)
: input.Clamp(minValue, maxValue);
/// <summary> Set the value of the slider without invoking OnValueChanged callback </summary>
/// <param name="input"> The new value for the slider </param>
public virtual void SetValueWithoutNotify(float input) =>
SetValue(input, false);
/// <summary> Set the value of the slider </summary>
/// <param name="newValue"> The new value for the slider </param>
/// <param name="sendCallback"> If the OnValueChanged callback should be invoked </param>
/// <remarks>
/// Process the input to ensure the value is between min and max value. If the input is different set the value and send the callback is required.
/// </remarks>
public void SetValue(float newValue, bool sendCallback = true)
{
bool valueChanged = Math.Abs(Value - newValue) > TOLERANCE; //check if the value has changed
float previousValue = Value;
Value = Mathf.Clamp(newValue, minValue, maxValue); //set the new value
if (wholeNumbers) Value = Value.Round(0); //round the value if wholeNumbers is true
UpdateLabel(valueLabel, Value);
UpdateVisuals();
if (valueChanged)
{
if (sendCallback)
{
UISystemProfilerApi.AddMarker($"{nameof(UISlider)}.{nameof(value)}", this);
#pragma warning disable CS0618
OnValueChangedCallback.Invoke(Value);
#pragma warning restore CS0618
OnValueChanged?.Invoke(Value);
stream.SendSignal(Value);
if (previousValue < Value)
{
OnValueIncremented?.Invoke(Value - previousValue);
stream.SendSignal(new UISliderSignalData(Id.Category, Id.Name, SliderState.ValueIncremented, this));
}
else if (previousValue > Value)
{
OnValueDecremented?.Invoke(previousValue - Value);
stream.SendSignal(new UISliderSignalData(Id.Category, Id.Name, SliderState.ValueDecremented, this));
}
}
if (InstantProgressorUpdate)
{
UpdateTargetProgressorValue();
}
else
{
PlayTargetProgressorValue();
}
}
if (!sendCallback) return;
if (Value <= minValue)
{
//value is equal to the min value
//invoke the OnValueReachedMin event if the value is equal to the min value
OnValueReachedMin.Execute();
//stream.SendSignal(new UISliderSignalData(Id.Category, Id.Name, SliderState.ReachedMinValue, this));
}
if (Value >= maxValue)
{
//value is equal to the max value
//invoke the OnValueReachedMax event if the value is equal to the max value
OnValueReachedMax.Execute();
//stream.SendSignal(new UISliderSignalData(Id.Category, Id.Name, SliderState.ReachedMaxValue, this));
}
}
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
//this can be invoked before OnEnabled is called
//we shouldn't be accessing other objects, before OnEnable is called
if (!IsActive()) return;
UpdateVisuals();
}
/// <summary>
/// Force-update the slider.
/// Useful if the properties changed and a visual update is needed.
/// </summary>
public void UpdateVisuals()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
UpdateCachedReferences();
#endif //UNITY_EDITOR
m_Tracker.Clear();
if (m_FillContainerRect != null)
{
m_Tracker.Add(this, FillRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
if (m_FillImage != null && m_FillImage.type == Image.Type.Filled)
{
m_FillImage.fillAmount = normalizedValue;
}
else
{
if (reverseValue)
anchorMin[(int)axis] = 1 - normalizedValue;
else
anchorMax[(int)axis] = normalizedValue;
}
FillRect.anchorMin = anchorMin;
FillRect.anchorMax = anchorMax;
}
if (m_HandleContainerRect == null)
return;
{
m_Tracker.Add(this, HandleRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
anchorMin[(int)axis] = anchorMax[(int)axis] = (reverseValue ? (1 - normalizedValue) : normalizedValue);
HandleRect.anchorMin = anchorMin;
HandleRect.anchorMax = anchorMax;
}
}
/// <summary> Update the slider's position based on the pointer event data </summary>
/// <param name="eventData"> Data </param>
/// <param name="cam"> Camera </param>
private void UpdateDrag(PointerEventData eventData, Camera cam)
{
RectTransform clickRect = m_HandleContainerRect ? m_HandleContainerRect : m_FillContainerRect;
if (clickRect == null)
return;
if (!(clickRect.rect.size[(int)axis] > 0))
return;
Vector2 position = Vector2.zero;
if (!MultipleDisplayUtilities.GetRelativeMousePositionForDrag(eventData, ref position))
return;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, position, cam, out Vector2 localCursor))
return;
Rect rect = clickRect.rect;
localCursor -= rect.position;
float val = Mathf.Clamp01((localCursor - m_Offset)[(int)axis] / rect.size[(int)axis]);
normalizedValue = reverseValue ? 1f - val : val;
}
private bool AllowDrag(PointerEventData eventData) =>
IsActive() &&
IsInteractable() &&
eventData.button == PointerEventData.InputButton.Left;
public override void OnPointerDown(PointerEventData eventData)
{
if (!AllowDrag(eventData))
return;
base.OnPointerDown(eventData);
m_Offset = Vector2.zero;
if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(HandleRect, eventData.pointerPressRaycast.screenPosition, eventData.enterEventCamera))
{
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(HandleRect, eventData.pointerPressRaycast.screenPosition, eventData.pressEventCamera, out Vector2 localMousePos))
{
m_Offset = localMousePos;
}
return;
}
// Outside the slider handle - jump to this point instead
UpdateDrag(eventData, eventData.pressEventCamera);
}
public virtual void OnDrag(PointerEventData eventData)
{
if (!AllowDrag(eventData))
return;
UpdateDrag(eventData, eventData.pressEventCamera);
}
public override void OnMove(AxisEventData eventData)
{
if (!IsActive() || !IsInteractable())
{
base.OnMove(eventData);
return;
}
switch (eventData.moveDir)
{
case MoveDirection.Left:
if (axis == Axis.Horizontal && FindSelectableOnLeft() == null)
SetValue(reverseValue ? value + stepSize : value - stepSize);
else
base.OnMove(eventData);
break;
case MoveDirection.Right:
if (axis == Axis.Horizontal && FindSelectableOnRight() == null)
SetValue(reverseValue ? value - stepSize : value + stepSize);
else
base.OnMove(eventData);
break;
case MoveDirection.Up:
if (axis == Axis.Vertical && FindSelectableOnUp() == null)
SetValue(reverseValue ? value - stepSize : value + stepSize);
else
base.OnMove(eventData);
break;
case MoveDirection.Down:
if (axis == Axis.Vertical && FindSelectableOnDown() == null)
SetValue(reverseValue ? value + stepSize : value - stepSize);
else
base.OnMove(eventData);
break;
}
}
/// <summary>
/// See Selectable.FindSelectableOnLeft
/// </summary>
public override Selectable FindSelectableOnLeft()
{
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
return null;
return base.FindSelectableOnLeft();
}
/// <summary>
/// See Selectable.FindSelectableOnRight
/// </summary>
public override Selectable FindSelectableOnRight()
{
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
return null;
return base.FindSelectableOnRight();
}
/// <summary>
/// See Selectable.FindSelectableOnUp
/// </summary>
public override Selectable FindSelectableOnUp()
{
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
return null;
return base.FindSelectableOnUp();
}
/// <summary>
/// See Selectable.FindSelectableOnDown
/// </summary>
public override Selectable FindSelectableOnDown()
{
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
return null;
return base.FindSelectableOnDown();
}
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
{
eventData.useDragThreshold = false;
}
/// <summary>
/// Sets the direction of this slider, optionally changing the layout as well.
/// </summary>
/// <param name="previousDirection">The previous direction of the slider.</param>
/// <param name="newDirection">The new direction of the slider.</param>
/// <param name="includeRectLayouts">Should the layout be flipped together with the slider direction</param>
public void SetDirection(SlideDirection previousDirection, SlideDirection newDirection, bool includeRectLayouts)
{
bool previousReverse = reverseValue;
Axis previousAxis = GetAxis(previousDirection);
direction = newDirection;
if (!includeRectLayouts)
return;
if (axis != previousAxis)
RectTransformUtility.FlipLayoutAxes(transform as RectTransform, true, true);
if (reverseValue != previousReverse)
RectTransformUtility.FlipLayoutOnAxis(transform as RectTransform, (int)axis, true, true);
}
private void UpdateTargetProgressorMinMax()
{
if (!targetProgressor) return;
targetProgressor.fromValue = minValue;
targetProgressor.toValue = maxValue;
targetProgressor.SetValueAt(value);
}
private void UpdateTargetProgressorValue()
{
if (!targetProgressor) return;
targetProgressor.SetValueAt(value);
}
private void PlayTargetProgressorValue()
{
if (!targetProgressor) return;
targetProgressor.PlayToValue(value);
}
#region Chainable Methods
/// <summary> Reference a new TMP_Text to the value label </summary>
/// <param name="label"> The TMP_Text to reference </param>
public T SetValueLabel<T>(TMP_Text label) where T : UISlider
{
valueLabel = label;
return (T)this;
}
/// <summary> Reference a new TMP_Text to the min value label </summary>
/// <param name="label"> The TMP_Text to reference </param>
public T SetMinValueLabel<T>(TMP_Text label) where T : UISlider
{
minValueLabel = label;
return (T)this;
}
/// <summary> Reference a new TMP_Text to the max value label </summary>
/// <param name="label"> The TMP_Text to reference </param>
public T SetMaxValueLabel<T>(TMP_Text label) where T : UISlider
{
maxValueLabel = label;
return (T)this;
}
/// <summary> Set a new current value for the slider </summary>
/// <param name="newValue"> The new value to set </param>
public T SetValue<T>(float newValue) where T : UISlider
{
value = newValue;
return (T)this;
}
/// <summary> Set a new min value </summary>
/// <param name="newMinValue"> The new min value </param>
public T SetMinValue<T>(float newMinValue) where T : UISlider
{
minValue = newMinValue;
return (T)this;
}
/// <summary> Set a new max value </summary>
/// <param name="newMaxValue"> The new max value </param>
public T SetMaxValue<T>(float newMaxValue) where T : UISlider
{
maxValue = newMaxValue;
return (T)this;
}
/// <summary> Set a new default value (reset value) </summary>
/// <param name="newResetValue"> The new default value (reset value) </param>
public T SetDefaultValue<T>(float newResetValue) where T : UISlider
{
defaultValue = newResetValue;
return (T)this;
}
/// <summary> Set a new target progressor to update when the value changes </summary>
/// <param name="progressor"> The new target progressor to update when the value changes </param>
public T SetTargetProgressor<T>(Progressor progressor) where T : UISlider
{
targetProgressor = progressor;
return (T)this;
}
#endregion
#region Static Methods
/// <summary> Get all the registered sliders with the given category and name </summary>
/// <param name="category"> UISlider category </param>
/// <param name="name"> UISlider name (from the given category) </param>
public static IEnumerable<UISlider> GetSliders(string category, string name) =>
database.Where(slider => slider.Id.Category.Equals(category)).Where(slider => slider.Id.Name.Equals(name));
/// <summary> Get all the registered sliders with the given category </summary>
/// <param name="category"> UISlider category </param>
public static IEnumerable<UISlider> GetAllSlidersInCategory(string category) =>
database.Where(slider => slider.Id.Category.Equals(category));
/// <summary> Get all the sliders that are active and enabled (all the visible/available sliders) </summary>
public static IEnumerable<UISlider> GetAvailableSliders() =>
database.Where(slider => slider.isActiveAndEnabled);
/// <summary> Get the selected slider (if a slider is not selected, this method returns null) </summary>
public static UISlider GetSelectedSlider() =>
database.FirstOrDefault(slider => slider.isSelected);
/// <summary> Select the slider with the given category and name (if it is active and enabled) </summary>
/// <param name="category"> UISlider category </param>
/// <param name="name"> UISlider name (from the given category) </param>
public static bool SelectSlider(string category, string name)
{
UISlider slider = availableSliders.FirstOrDefault(b => b.Id.Category.Equals(category) & b.Id.Name.Equals(name));
if (slider == null) return false;
slider.Select();
return true;
}
/// <summary> Update a value label text with the given value </summary>
/// <param name="targetLabel"> Label to update </param>
/// <param name="displayValue"> Value to display </param>
private static void UpdateLabel(TMP_Text targetLabel, float displayValue)
{
if (targetLabel == null) return;
targetLabel.text = displayValue.ToString(CultureInfo.InvariantCulture);
}
#endregion
}
}