using System.Collections; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace UIWidgets { public class Switch : Selectable, ISubmitHandler, IPointerClickHandler, IEventSystemHandler { [SerializeField] protected bool isOn; [SerializeField] protected SwitchDirection direction; [SerializeField] public RectTransform Mark; [SerializeField] public Image Background; [SerializeField] private Color backgroundOnColor = new Color(1f, 1f, 1f, 1f); [SerializeField] private Color backgroundOffColor = new Color(1f, 43f / 51f, 23f / 51f, 1f); [SerializeField] public float AnimationDuration = 0.3f; [SerializeField] public SwitchEvent OnValueChanged = new SwitchEvent(); protected Coroutine CurrentCorutine; public bool IsOn { get { return isOn; } set { if (isOn != value) { isOn = value; Changed(); } } } public SwitchDirection Direction { get { return direction; } set { direction = value; SetMarkPosition(false); } } public Color BackgroundOnColor { get { return backgroundOnColor; } set { backgroundOnColor = value; SetBackgroundColor(); } } public Color BackgroundOffColor { get { return backgroundOffColor; } set { backgroundOffColor = value; SetBackgroundColor(); } } protected virtual void Changed() { SetMarkPosition(); SetBackgroundColor(); OnValueChanged.Invoke(IsOn); } protected virtual void SetMarkPosition(bool animate = true) { if (CurrentCorutine != null) { StopCoroutine(CurrentCorutine); } if (animate) { StartCoroutine(AnimateSwitch(IsOn, AnimationDuration)); } else { SetMarkPosition(GetPosition(IsOn)); } } protected virtual IEnumerator AnimateSwitch(bool state, float time) { SetMarkPosition(GetPosition(!IsOn)); float prev_position = GetPosition(!IsOn); float next_position = GetPosition(IsOn); float end_time = Time.time + time; while (Time.time <= end_time) { float distance = 1f - (end_time - Time.time) / time; float pos = Mathf.Lerp(prev_position, next_position, distance); SetMarkPosition(pos); yield return null; } SetMarkPosition(GetPosition(IsOn)); } protected virtual void SetMarkPosition(float position) { if (!(Mark == null)) { if (IsHorizontal()) { Mark.anchorMin = new Vector2(position, Mark.anchorMin.y); Mark.anchorMax = new Vector2(position, Mark.anchorMax.y); Mark.pivot = new Vector2(position, Mark.pivot.y); } else { Mark.anchorMin = new Vector2(Mark.anchorMin.x, position); Mark.anchorMax = new Vector2(Mark.anchorMax.x, position); Mark.pivot = new Vector2(Mark.pivot.x, position); } } } protected bool IsHorizontal() { return Direction == SwitchDirection.LeftToRight || Direction == SwitchDirection.RightToLeft; } protected float GetPosition(bool state) { switch (Direction) { case SwitchDirection.LeftToRight: case SwitchDirection.BottomToTop: return (!state) ? 0f : 1f; case SwitchDirection.RightToLeft: case SwitchDirection.TopToBottom: return (!state) ? 1f : 0f; default: return 0f; } } protected virtual void SetBackgroundColor() { if (!(Background == null)) { Background.color = ((!IsOn) ? BackgroundOffColor : BackgroundOnColor); } } protected virtual void CallChanged() { if (IsActive() && IsInteractable()) { IsOn = !IsOn; } } public virtual void OnSubmit(BaseEventData eventData) { CallChanged(); } public virtual void OnPointerClick(PointerEventData eventData) { if (eventData.button == PointerEventData.InputButton.Left) { CallChanged(); } } } }