322 lines
8.8 KiB
C#
322 lines
8.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using AlicizaX;
|
|
using AlicizaX.UI.Extension;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.Serialization;
|
|
using UnityEngine.UI;
|
|
using AudioType = AlicizaX.Audio.Runtime.AudioType;
|
|
|
|
[Serializable]
|
|
public enum ButtonModeType
|
|
{
|
|
Normal,
|
|
Toggle
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class TransitionData
|
|
{
|
|
public Graphic targetGraphic;
|
|
public Selectable.Transition transition = Selectable.Transition.ColorTint;
|
|
public ColorBlock colors;
|
|
public SpriteState spriteState;
|
|
}
|
|
|
|
[Serializable]
|
|
public struct ButtonSoundData
|
|
{
|
|
public ButtonSoundType ButtonSoundType;
|
|
public string ButtonUISoundName;
|
|
}
|
|
|
|
|
|
internal enum SelectionState
|
|
{
|
|
/// <summary>
|
|
/// The UI object can be selected.
|
|
/// </summary>
|
|
Normal,
|
|
|
|
/// <summary>
|
|
/// The UI object is highlighted.
|
|
/// </summary>
|
|
Highlighted,
|
|
|
|
/// <summary>
|
|
/// The UI object is pressed.
|
|
/// </summary>
|
|
Pressed,
|
|
|
|
/// <summary>
|
|
/// The UI object is selected
|
|
/// </summary>
|
|
Selected,
|
|
|
|
/// <summary>
|
|
/// The UI object cannot be selected.
|
|
/// </summary>
|
|
Disabled,
|
|
}
|
|
|
|
[DisallowMultipleComponent]
|
|
[RequireComponent(typeof(Graphic))]
|
|
public class UXButton : UIBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler
|
|
{
|
|
[SerializeField] private bool m_Interactable = true;
|
|
|
|
|
|
[SerializeField] private ButtonModeType m_Mode;
|
|
|
|
[SerializeField] private UnityEvent m_OnClick = new UnityEvent();
|
|
|
|
[SerializeField] private TransitionData m_TransitionData = new TransitionData();
|
|
|
|
[SerializeField] private List<TransitionData> m_ChildTransitions = new List<TransitionData>();
|
|
[SerializeField] private UXGroup m_UXGroup;
|
|
|
|
[SerializeField] private List<ButtonSoundCell> m_ButtonUISounds = new List<ButtonSoundCell>();
|
|
|
|
private SelectionState m_SelectionState = SelectionState.Normal;
|
|
private bool m_ExistUI;
|
|
private bool m_IsDown;
|
|
private bool m_IsTogSelected;
|
|
|
|
|
|
public bool IsSelected
|
|
{
|
|
get { return m_IsTogSelected; }
|
|
internal set
|
|
{
|
|
m_IsTogSelected = value;
|
|
onValueChanged?.Invoke(m_IsTogSelected);
|
|
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
|
UpdateVisualState(m_SelectionState, false);
|
|
}
|
|
}
|
|
|
|
|
|
public UnityEvent onClick
|
|
{
|
|
get { return m_OnClick; }
|
|
set { m_OnClick = value; }
|
|
}
|
|
|
|
[SerializeField] private UnityEvent<bool> m_OnValueChanged = new UnityEvent<bool>();
|
|
|
|
public UnityEvent<bool> onValueChanged
|
|
{
|
|
get { return m_OnValueChanged; }
|
|
set { m_OnValueChanged = value; }
|
|
}
|
|
|
|
protected override void Awake()
|
|
{
|
|
base.Awake();
|
|
if (m_Mode == ButtonModeType.Toggle)
|
|
{
|
|
onValueChanged?.Invoke(IsSelected);
|
|
}
|
|
}
|
|
|
|
|
|
void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
|
|
{
|
|
if (!m_Interactable) return;
|
|
m_IsDown = true;
|
|
m_SelectionState = SelectionState.Pressed;
|
|
UpdateVisualState(m_SelectionState, false);
|
|
PlayButtonSound(ButtonSoundType.Down);
|
|
}
|
|
|
|
void IPointerUpHandler.OnPointerUp(PointerEventData eventData)
|
|
{
|
|
if (!m_Interactable) return;
|
|
m_IsDown = false;
|
|
|
|
if (!m_IsTogSelected)
|
|
{
|
|
m_SelectionState = m_ExistUI ? SelectionState.Normal : SelectionState.Highlighted;
|
|
UpdateVisualState(m_SelectionState, false);
|
|
}
|
|
else
|
|
{
|
|
m_SelectionState = SelectionState.Selected;
|
|
UpdateVisualState(m_SelectionState, false);
|
|
}
|
|
|
|
if (!m_ExistUI)
|
|
{
|
|
ProcessClick();
|
|
}
|
|
|
|
PlayButtonSound(ButtonSoundType.Up);
|
|
}
|
|
|
|
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData)
|
|
{
|
|
if (!m_Interactable || CantTouch()) return;
|
|
m_SelectionState = SelectionState.Highlighted;
|
|
m_ExistUI = false;
|
|
UpdateVisualState(m_SelectionState, false);
|
|
PlayButtonSound(ButtonSoundType.Enter);
|
|
}
|
|
|
|
void IPointerExitHandler.OnPointerExit(PointerEventData eventData)
|
|
{
|
|
if (!m_Interactable) return;
|
|
if (m_IsDown)
|
|
{
|
|
m_ExistUI = true;
|
|
return;
|
|
}
|
|
|
|
if (CantTouch())
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_SelectionState = SelectionState.Normal;
|
|
|
|
UpdateVisualState(m_SelectionState, false);
|
|
PlayButtonSound(ButtonSoundType.Exit);
|
|
}
|
|
|
|
private bool CantTouch()
|
|
{
|
|
return m_Mode == ButtonModeType.Toggle && m_IsTogSelected;
|
|
}
|
|
|
|
public void SetSelect(bool state, bool boardEvent = false)
|
|
{
|
|
if (m_Mode != ButtonModeType.Toggle) return;
|
|
m_IsTogSelected = state;
|
|
if (boardEvent) onValueChanged?.Invoke(m_IsTogSelected);
|
|
m_SelectionState = m_IsTogSelected ? SelectionState.Selected : SelectionState.Normal;
|
|
UpdateVisualState(m_SelectionState, false);
|
|
}
|
|
|
|
private void ProcessClick()
|
|
{
|
|
if (m_Mode == ButtonModeType.Normal)
|
|
{
|
|
onClick?.Invoke();
|
|
}
|
|
else
|
|
{
|
|
if (m_UXGroup)
|
|
{
|
|
m_UXGroup.NotifyButtonClicked(this);
|
|
return;
|
|
}
|
|
|
|
IsSelected = !IsSelected;
|
|
}
|
|
}
|
|
|
|
private void UpdateVisualState(SelectionState state, bool instant)
|
|
{
|
|
ProcessTransitionData(m_TransitionData, state, instant);
|
|
foreach (var transition in m_ChildTransitions)
|
|
{
|
|
ProcessTransitionData(transition, state, instant);
|
|
}
|
|
}
|
|
|
|
|
|
private void ProcessTransitionData(TransitionData transition, SelectionState state, bool instant)
|
|
{
|
|
if (transition.targetGraphic == null) return;
|
|
|
|
Color tintColor;
|
|
Sprite transitionSprite;
|
|
switch (state)
|
|
{
|
|
case SelectionState.Normal:
|
|
tintColor = transition.colors.normalColor;
|
|
transitionSprite = null;
|
|
break;
|
|
case SelectionState.Highlighted:
|
|
tintColor = transition.colors.highlightedColor;
|
|
transitionSprite = transition.spriteState.highlightedSprite;
|
|
break;
|
|
case SelectionState.Pressed:
|
|
tintColor = transition.colors.pressedColor;
|
|
transitionSprite = transition.spriteState.pressedSprite;
|
|
break;
|
|
case SelectionState.Selected:
|
|
tintColor = transition.colors.selectedColor;
|
|
transitionSprite = transition.spriteState.selectedSprite;
|
|
break;
|
|
case SelectionState.Disabled:
|
|
tintColor = transition.colors.disabledColor;
|
|
transitionSprite = transition.spriteState.disabledSprite;
|
|
break;
|
|
default:
|
|
tintColor = Color.black;
|
|
transitionSprite = null;
|
|
break;
|
|
}
|
|
|
|
switch (transition.transition)
|
|
{
|
|
case Selectable.Transition.ColorTint:
|
|
StartColorTween(transition, tintColor * transition.colors.colorMultiplier, instant);
|
|
break;
|
|
case Selectable.Transition.SpriteSwap:
|
|
DoSpriteSwap(transition, transitionSprite);
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected void StartColorTween(TransitionData transitionData, Color targetColor, bool instant)
|
|
{
|
|
if (Application.isPlaying)
|
|
{
|
|
transitionData.targetGraphic.CrossFadeColor(targetColor, instant ? 0f : transitionData.colors.fadeDuration, true, true);
|
|
}
|
|
else
|
|
{
|
|
transitionData.targetGraphic.canvasRenderer.SetColor(targetColor);
|
|
}
|
|
}
|
|
|
|
protected void DoSpriteSwap(TransitionData transitionData, Sprite newSprite)
|
|
{
|
|
if (transitionData.targetGraphic is Image image)
|
|
{
|
|
image.overrideSprite = newSprite;
|
|
}
|
|
else if (transitionData.targetGraphic != null)
|
|
{
|
|
Log.Error($"Target Graphic must be Image for SpriteSwap. Object: {transitionData.targetGraphic.name}");
|
|
}
|
|
}
|
|
|
|
protected void PlayButtonSound(ButtonSoundType buttonSoundType)
|
|
{
|
|
ButtonSoundCell buttonSound = GetButtonSound(buttonSoundType);
|
|
if (buttonSound == null || string.IsNullOrEmpty(buttonSound.ButtonUISoundName))
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameApp.Audio.Play(AudioType.UISound, buttonSound.ButtonUISoundName, false, GameApp.Audio.UISoundVolume, true);
|
|
}
|
|
|
|
protected ButtonSoundCell GetButtonSound(ButtonSoundType buttonSoundType)
|
|
{
|
|
foreach (var buttonSound in m_ButtonUISounds)
|
|
{
|
|
if (buttonSound.ButtonSoundType == buttonSoundType)
|
|
{
|
|
return buttonSound;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|