2025-07-08 10:46:31 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|