Files
EnglewoodLAB/Assets/Scripts/UVC/UI/Tooltip/TooltipHandler.cs

183 lines
9.3 KiB
C#

using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems; // IPointerEnterHandler, IPointerExitHandler 인터페이스 사용
using UnityEngine.UI; // Selectable 컴포넌트 사용 (버튼 등의 상호작용 가능 여부 확인)
namespace UVC.UI.Tooltip
{
/// <summary>
/// UI 요소에 부착하여 마우스 오버 시 툴팁을 표시하고 마우스 아웃 시 툴팁을 숨기는 기능을 제공합니다.
/// TooltipManager와 함께 작동하며, 마우스 이벤트 감지 후 TooltipManager에 툴팁 관리를 위임합니다.
///
/// 사용 방법:
/// 1. 툴팁을 표시하고자 하는 UI 요소(예: Button, Image 등)에 이 컴포넌트를 추가합니다.
/// 2. Inspector 창이나 코드를 통해 'Tooltip' 프로퍼티에 표시할 텍스트 또는 다국어 키를 설정합니다.
/// 3. TooltipManager가 초기화되어 있어야 하며, 이 핸들러의 액션들을 TooltipManager의 메서드에 연결해야 합니다.
/// (일반적으로 다른 관리 클래스(예: ToolbarView)에서 이 연결을 수행합니다.)
///
/// 예시 (ToolbarView.cs에서의 설정 부분):
/// <code>
/// // ... ToolbarView.cs 내에서 버튼 생성 시 ...
/// GameObject buttonGameObject = Instantiate(buttonPrefab);
/// TooltipHandler tooltipHandler = buttonGameObject.AddComponent<TooltipHandler>();
/// tooltipHandler.Tooltip = "my_tooltip_key"; // 표시할 툴팁 내용 또는 다국어 키
///
/// // TooltipManager의 메서드와 연결
/// if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized)
/// {
/// tooltipHandler.OnPointerEnterAction = TooltipManager.Instance.HandlePointerEnter;
/// tooltipHandler.OnPointerExitAction = TooltipManager.Instance.HandlePointerExit;
/// }
/// </code>
/// </summary>
public class TooltipHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
/// <summary>
/// 마우스 포인터가 UI 요소에 진입했을 때 호출될 액션입니다.
/// TooltipManager.Instance.HandlePointerEnter 메서드에 연결됩니다.
/// 첫 번째 string 매개변수는 툴팁 내용(또는 키), 두 번째 Vector3는 마우스 위치입니다.
/// </summary>
public System.Action<string, Vector3> OnPointerEnterAction;
/// <summary>
/// 마우스 포인터가 UI 요소에서 벗어났을 때 호출될 액션입니다.
/// TooltipManager.Instance.HandlePointerExit 메서드에 연결됩니다.
/// </summary>
public System.Action OnPointerExitAction;
/// <summary>
/// 이 UI 요소에 표시될 툴팁의 내용 또는 다국어 키입니다.
/// Inspector에서 직접 설정하거나 코드로 할당할 수 있습니다.
/// </summary>
/// <example>
/// <code>
/// TooltipHandler handler = myButton.GetComponent<TooltipHandler>();
/// if (handler != null)
/// {
/// handler.Tooltip = "버튼_설명_키"; // 다국어 키 사용
/// // 또는 handler.Tooltip = "이 버튼은 저장 기능을 수행합니다."; // 직접 텍스트 사용
/// }
/// </code>
/// </example>
public string Tooltip { get; set; }
private Coroutine _showTooltipCoroutine; // 툴팁 표시 지연을 위한 코루틴 참조
private const float TooltipDelay = 0.5f; // 툴팁 표시까지의 지연 시간 (초 단위)
private const float MouseMoveThreshold = 5f; // 마우스 이동 감지 임계값 (픽셀 단위)
/// <summary>
/// 마우스 포인터가 이 UI 요소의 영역 안으로 들어왔을 때 호출됩니다. (IPointerEnterHandler 인터페이스 구현)
/// 설정된 Tooltip 내용이 있고, 연결된 Selectable 컴포넌트가 상호작용 가능 상태일 때만 작동합니다.
/// 지정된 지연 시간(TooltipDelay) 후에 OnPointerEnterAction을 호출하여 툴팁 표시를 요청합니다.
/// </summary>
/// <param name="eventData">포인터 이벤트 데이터입니다.</param>
public void OnPointerEnter(PointerEventData eventData)
{
// 툴팁 내용이 있고, 이 게임오브젝트에 Selectable 컴포넌트가 있거나 없거나, 있다면 interactable 상태일 때만
//Selectable selectable = gameObject.GetComponent<Selectable>();
if (!string.IsNullOrEmpty(Tooltip))// && (selectable == null || selectable.interactable))
{
// 이전에 실행 중이던 코루틴이 있다면 중지 (빠르게 들어왔다 나갔다 반복하는 경우 대비)
if (_showTooltipCoroutine != null)
{
StopCoroutine(_showTooltipCoroutine);
}
// 새 코루틴 시작하여 지연 후 툴팁 표시
_showTooltipCoroutine = StartCoroutine(ShowTooltipAfterDelayCoroutine(Tooltip, Input.mousePosition));
}
}
/// <summary>
/// 지정된 시간(TooltipDelay)만큼 대기한 후, OnPointerEnterAction을 호출하여 툴팁 표시를 요청하는 코루틴입니다.
/// </summary>
/// <param name="tooltip">표시할 툴팁 내용 또는 다국어 키입니다.</param>
/// <param name="initialMousePosition">현재 마우스 포인터의 화면 좌표입니다.</param>
private IEnumerator ShowTooltipAfterDelayCoroutine(string tooltip, Vector3 initialMousePosition)
{
float stillTime = 0f; // 마우스가 움직이지 않은 시간
Vector3 lastMousePosition = initialMousePosition;
while (stillTime < TooltipDelay)
{
// 현재 마우스 위치와 마지막 기록된 위치 간의 거리 계산
float distance = Vector3.Distance(Input.mousePosition, lastMousePosition);
// 거리가 임계값을 초과하면 마우스가 움직인 것으로 간주
if (distance > MouseMoveThreshold)
{
// 마우스가 움직였으므로 정지 시간을 리셋
stillTime = 0f;
lastMousePosition = Input.mousePosition;
}
else
{
// 마우스가 거의 움직이지 않으면 정지 시간 증가
stillTime += Time.unscaledDeltaTime;
}
yield return null; // 다음 프레임까지 대기
}
// TooltipDelay 시간 동안 마우스가 거의 움직이지 않았으면 툴팁 표시
_showTooltipCoroutine = null; // 코루틴 완료 후 참조 null 처리
OnPointerEnterAction?.Invoke(tooltip, Input.mousePosition); // 현재 마우스 위치 사용
// TooltipManager의 메서드와 연결
if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized)
{
TooltipManager.Instance.HandlePointerEnter(tooltip, Input.mousePosition);
}
}
/// <summary>
/// 마우스 포인터가 이 UI 요소의 영역 밖으로 나갔을 때 호출됩니다. (IPointerExitHandler 인터페이스 구현)
/// 실행 중인 툴팁 표시 코루틴이 있다면 중지하고, OnPointerExitAction을 호출하여 툴팁 숨김을 요청합니다.
/// </summary>
/// <param name="eventData">포인터 이벤트 데이터입니다.</param>
public void OnPointerExit(PointerEventData eventData)
{
// 실행 중인 툴팁 표시 코루틴이 있다면 중지 (마우스가 나가면 지연 중이던 툴팁 표시 취소)
if (_showTooltipCoroutine != null)
{
StopCoroutine(_showTooltipCoroutine);
_showTooltipCoroutine = null;
}
OnPointerExitAction?.Invoke(); // 연결된 액션 호출 (TooltipManager.HandlePointerExit)
if (TooltipManager.Instance != null && TooltipManager.Instance.IsInitialized)
{
TooltipManager.Instance.HandlePointerExit();
}
}
/// <summary>
/// 이 MonoBehaviour가 비활성화될 때 호출됩니다.
/// 실행 중인 코루틴이 있다면 정리합니다.
/// </summary>
private void OnDisable()
{
if (_showTooltipCoroutine != null)
{
StopCoroutine(_showTooltipCoroutine);
_showTooltipCoroutine = null;
}
// 만약 OnPointerExitAction이 즉시 호출되어야 한다면 아래 코드 추가
// OnPointerExitAction?.Invoke();
}
/// <summary>
/// 이 MonoBehaviour가 파괴될 때 호출됩니다.
/// 실행 중인 코루틴이 있다면 정리합니다.
/// </summary>
private void OnDestroy()
{
if (_showTooltipCoroutine != null)
{
StopCoroutine(_showTooltipCoroutine);
_showTooltipCoroutine = null;
}
// OnPointerEnterAction 및 OnPointerExitAction 참조 해제 (필요 시)
OnPointerEnterAction = null;
OnPointerExitAction = null;
}
}
}