ProjectDDD/Assets/_Datas/SLShared/SLUnity/SLUI/SLUIButton.cs
2025-06-17 20:47:57 +09:00

351 lines
10 KiB (Stored with Git LFS)
C#

using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace Superlazy.UI
{
[RequireComponent(typeof(Button))]
public class SLUIButton : SLUIComponent, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, ISelectHandler, IDeselectHandler
{
public static Material grayMaterial;
public static Material grayTextMaterial;
public static DateTime globalClickedTime = DateTime.MinValue;
public static PointerEventData currentPoint;
public string command;
public bool useGrayScale;
public bool focus;
public string focusBind;
public bool selectIsHover;
public bool fastClick;
public SLValueComparison comparison;
public string clickSound = "SoundEffect/SE_UI_click";
[NonSerialized]
public Button button;
private Graphic[] childImages;
private Color[] childImageColors; // TODO: SLUIColorSelect 대비해야함
private TextMeshProUGUI[] childTexts;
private Color[] childTextColors;
private DateTime clickedTime = DateTime.MinValue;
private enum ButtonState
{
Normal,
Highlighted,
Pressed,
Disabled
}
private ButtonState currentButtonState;
private bool isPointerInside;
private bool isPointerDown;
protected override void Validate()
{
button = GetComponent<Button>();
childImages = GetComponentsInChildren<Image>(true).Where(i => i.transform != transform).ToArray();
childImageColors = new Color[childImages.Length];
var i = 0;
foreach (var image in childImages)
{
childImageColors[i] = image.color;
i += 1;
}
childTexts = GetComponentsInChildren<TextMeshProUGUI>(true).Where(i => i.transform != transform).ToArray();
childTextColors = new Color[childTexts.Length];
i = 0;
foreach (var text in childTexts)
{
childTextColors[i] = text.color;
i += 1;
}
}
protected override void Init()
{
button.onClick.AddListener(ButtonAction);
}
public void ButtonAction()
{
if (bindParent.Active == false) return;
if (SLUIDragButton.globalDragging) // 글로벌 드래그중 버튼을 눌러도 풀려야함
{
var point = currentPoint;
var canvas = GetComponentInParent<Canvas>();
Camera uiCamera;
if (canvas.renderMode == RenderMode.ScreenSpaceCamera || canvas.renderMode == RenderMode.WorldSpace)
{
uiCamera = canvas.worldCamera; // Camera가 필요함
}
else
{
uiCamera = null; // ScreenSpace-Overlay는 Camera가 필요 없음
}
point.position = RectTransformUtility.WorldToScreenPoint(uiCamera, transform.position);
SLUIDragButton.EndExternalDrag(point);
return;
}
if (fastClick == false)
{
var now = SLSystem.Now;
if (globalClickedTime.AddSeconds(0.1f) > now) return;
if (clickedTime.AddSeconds(0.15f) > now) return;
globalClickedTime = now;
clickedTime = now;
}
SLSound.PlaySound(clickSound, "UI", false, false, true, 0.5f);
if (string.IsNullOrEmpty(command)) return;
SLGame.Command(command, SLGame.SessionGet(bindParent.BindPath));
}
protected override void Enable()
{
if (comparison.useCheckValue)
{
comparison.OnEnable(bindParent.BindPath, OnChange);
}
else
{
if (focus && button.interactable)
{
button.Select();
}
}
if (string.IsNullOrEmpty(focusBind) == false)
{
SLGame.AddNotify(bindParent.BindPath.CombinePath(focusBind), OnFocusChange);
}
}
protected override void Disable()
{
if (comparison.useCheckValue)
{
comparison.OnDisable();
}
if (string.IsNullOrEmpty(focusBind) == false)
{
SLGame.RemoveNotify(bindParent.BindPath.CombinePath(focusBind), OnFocusChange);
}
}
private void OnChange()
{
if (bindParent.Active == false) return;
var sessionRoot = SLGame.SessionGet(bindParent.BindPath);
if (sessionRoot == false) return; // TEMP: 세션루트가 삭제되었지만, 삭제되되기전 코루틴 처리가 있을 수 있음
var result = true;
if (comparison.useCheckValue)
{
result = comparison.Result;
}
button.interactable = result;
if (focus && button.interactable)
{
button.Select();
}
if (string.IsNullOrEmpty(focusBind) == false)
{
OnFocusChange();
}
UpdateGrayScale();
}
private void UpdateGrayScale()
{
if (useGrayScale == false) return;
if (button.targetGraphic == null) return;
if (button.interactable && (button.targetGraphic.material == grayMaterial || button.targetGraphic.material == grayTextMaterial))
{
button.targetGraphic.material = null;
foreach (var child in childImages)
{
child.material = null;
}
foreach (var child in childTexts)
{
child.material = null;
}
}
else if (button.interactable == false && button.targetGraphic.material != grayMaterial && button.targetGraphic.mainTexture != grayTextMaterial)
{
button.targetGraphic.material = grayMaterial;
foreach (var child in childImages)
{
child.material = grayMaterial;
}
foreach (var child in childTexts)
{
child.material = grayTextMaterial;
}
}
}
public void OnPointerEnter(PointerEventData eventData)
{
currentPoint = eventData;
if (bindParent.Active == false) return;
if (button.interactable == false) return;
button.Select();
isPointerInside = true;
}
public void OnPointerExit(PointerEventData eventData)
{
currentPoint = eventData;
isPointerInside = false;
if (selectIsHover)
{
DeselectButton();
}
}
public void OnPointerDown(PointerEventData eventData)
{
currentPoint = eventData;
isPointerDown = true;
}
public void OnPointerUp(PointerEventData eventData)
{
currentPoint = eventData;
isPointerDown = false;
}
private void OnFocusChange()
{
if (bindParent.Active == false) return;
if (button.interactable == false) return;
bool focusResult = SLGame.SessionGet(bindParent.BindPath.CombinePath(focusBind));
if (focusResult)
{
button.Select();
}
else
{
DeselectButton();
}
}
private void DeselectButton()
{
if (EventSystem.current.currentSelectedGameObject == button.gameObject)
{
EventSystem.current.SetSelectedGameObject(null);
}
}
public void OnSelect(BaseEventData eventData)
{
if (bindParent.Active == false) return;
if (button.interactable == false) return;
if (string.IsNullOrEmpty(focusBind)) return;
SLGame.SessionGet(bindParent.BindPath).Set(focusBind, true);
}
public void OnDeselect(BaseEventData eventData)
{
if (bindParent.Active == false) return;
if (button.interactable == false) return;
if (string.IsNullOrEmpty(focusBind)) return;
SLGame.SessionGet(bindParent.BindPath).Set(focusBind, false);
}
private void Update()
{
if (button.transition != Selectable.Transition.ColorTint) return;
var newState = GetButtonState();
if (newState != currentButtonState)
{
currentButtonState = newState;
var color = button.colors.normalColor;
switch (currentButtonState)
{
case ButtonState.Normal:
color = button.colors.normalColor;
break;
case ButtonState.Highlighted:
color = button.colors.highlightedColor;
break;
case ButtonState.Pressed:
color = button.colors.pressedColor;
break;
case ButtonState.Disabled:
color = button.colors.disabledColor;
break;
}
var i = 0;
foreach (var image in childImages)
{
image.color = childImageColors[i] * color * button.colors.colorMultiplier;
i += 1;
}
i = 0;
foreach (var text in childTexts)
{
text.color = childTextColors[i] * color * button.colors.colorMultiplier;
i += 1;
}
}
}
private ButtonState GetButtonState()
{
if (!button.interactable)
{
return ButtonState.Disabled;
}
if (isPointerDown)
{
return ButtonState.Pressed;
}
if (isPointerInside)
{
return ButtonState.Highlighted;
}
return ButtonState.Normal;
}
}
}