362 lines
9.8 KiB
C#
362 lines
9.8 KiB
C#
using System.Collections;
|
|
using GeometryTD.CustomEvent;
|
|
using GeometryTD.Definition;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
|
|
namespace GeometryTD.UI
|
|
{
|
|
public class RepoItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
|
|
{
|
|
[SerializeField] private Image _highlightImage;
|
|
[SerializeField] private IconArea _iconArea;
|
|
|
|
private static readonly Color NormalColor = new Color32(40, 40, 40, 180);
|
|
private static readonly Color SelectedColor = new Color32(255, 216, 102, 255);
|
|
private static readonly Vector2 DefaultDragGhostSize = new Vector2(64f, 64f);
|
|
|
|
[SerializeField] private RepoItemContext _context;
|
|
private CanvasGroup _canvasGroup;
|
|
private RectTransform _dragRoot;
|
|
private GameObject _dragGhostObject;
|
|
private RectTransform _dragGhostRect;
|
|
private bool _isSelected;
|
|
private bool _isDragging;
|
|
private bool _dropHandled;
|
|
private bool _dropAssigned;
|
|
private Coroutine _pendingOpenDetailRoutine;
|
|
private bool _cancelPendingOpenDetail;
|
|
|
|
public RepoItemContext Context => _context;
|
|
|
|
private void Awake()
|
|
{
|
|
_canvasGroup = GetComponent<CanvasGroup>();
|
|
if (_canvasGroup == null)
|
|
{
|
|
_canvasGroup = gameObject.AddComponent<CanvasGroup>();
|
|
}
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
CancelPendingOpenDetail();
|
|
ResetDragState();
|
|
}
|
|
|
|
public void OnInit(RepoItemContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
OnReset();
|
|
return;
|
|
}
|
|
|
|
_context = context;
|
|
|
|
_iconArea.OnInit(context.IconAreaContext);
|
|
|
|
SetSelected(false);
|
|
ResetDragState();
|
|
}
|
|
|
|
public void OnReset()
|
|
{
|
|
CancelPendingOpenDetail();
|
|
_context = null;
|
|
_iconArea.OnReset();
|
|
|
|
SetSelected(false);
|
|
ResetDragState();
|
|
}
|
|
|
|
public void SetSelected(bool isSelected)
|
|
{
|
|
_isSelected = isSelected;
|
|
if (_highlightImage == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_highlightImage.color = isSelected ? SelectedColor : NormalColor;
|
|
}
|
|
|
|
public void OnClick()
|
|
{
|
|
if (_context == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_isDragging)
|
|
{
|
|
return;
|
|
}
|
|
|
|
StartPendingOpenDetail();
|
|
}
|
|
|
|
public void OnBeginDrag(PointerEventData eventData)
|
|
{
|
|
if (!CanStartDrag(eventData))
|
|
{
|
|
return;
|
|
}
|
|
|
|
_dragRoot = ResolveDragRoot();
|
|
if (_dragRoot == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_isDragging = true;
|
|
_dropHandled = false;
|
|
_dropAssigned = false;
|
|
_cancelPendingOpenDetail = true;
|
|
|
|
CloseItemDescFormIfOpen();
|
|
|
|
if (!CreateDragGhost())
|
|
{
|
|
_isDragging = false;
|
|
_dragRoot = null;
|
|
return;
|
|
}
|
|
|
|
if (_canvasGroup != null)
|
|
{
|
|
_canvasGroup.blocksRaycasts = false;
|
|
}
|
|
|
|
SetSelected(true);
|
|
UpdateDragGhostPosition(eventData);
|
|
}
|
|
|
|
public void OnDrag(PointerEventData eventData)
|
|
{
|
|
if (!_isDragging)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateDragGhostPosition(eventData);
|
|
}
|
|
|
|
public void OnEndDrag(PointerEventData eventData)
|
|
{
|
|
if (!_isDragging)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool assigned = _dropHandled && _dropAssigned;
|
|
_isDragging = false;
|
|
|
|
if (_canvasGroup != null)
|
|
{
|
|
_canvasGroup.blocksRaycasts = true;
|
|
}
|
|
DestroyDragGhost();
|
|
_dragRoot = null;
|
|
|
|
if (_context == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GameEntry.Event.Fire(this, RepoItemDragEndedEventArgs.Create(_context.InstanceId, assigned));
|
|
}
|
|
|
|
public void SetDropResult(bool assigned)
|
|
{
|
|
if (!_isDragging)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_dropHandled = true;
|
|
_dropAssigned = assigned;
|
|
}
|
|
|
|
private bool CanStartDrag(PointerEventData eventData)
|
|
{
|
|
if (_context == null || _isSelected || _isDragging)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (!_context.CanDrag)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_context.ComponentSlotType == TowerCompSlotType.None)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (eventData == null || eventData.button != PointerEventData.InputButton.Left)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void StartPendingOpenDetail()
|
|
{
|
|
CancelPendingOpenDetail();
|
|
_cancelPendingOpenDetail = false;
|
|
_pendingOpenDetailRoutine = StartCoroutine(WaitPointerReleaseAndOpenDetail());
|
|
}
|
|
|
|
private void CancelPendingOpenDetail()
|
|
{
|
|
_cancelPendingOpenDetail = true;
|
|
if (_pendingOpenDetailRoutine != null)
|
|
{
|
|
StopCoroutine(_pendingOpenDetailRoutine);
|
|
_pendingOpenDetailRoutine = null;
|
|
}
|
|
}
|
|
|
|
private IEnumerator WaitPointerReleaseAndOpenDetail()
|
|
{
|
|
while (IsPrimaryPointerPressed())
|
|
{
|
|
if (_cancelPendingOpenDetail || _isDragging)
|
|
{
|
|
_pendingOpenDetailRoutine = null;
|
|
yield break;
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
_pendingOpenDetailRoutine = null;
|
|
if (_cancelPendingOpenDetail || _isDragging || _context == null)
|
|
{
|
|
yield break;
|
|
}
|
|
|
|
GameEntry.Event.Fire(this,
|
|
RepoItemDetailRequestedEventArgs.Create(_context.InstanceId, transform.position));
|
|
}
|
|
|
|
private static bool IsPrimaryPointerPressed()
|
|
{
|
|
if (Input.GetMouseButton(0))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return Input.touchCount > 0;
|
|
}
|
|
|
|
private static void CloseItemDescFormIfOpen()
|
|
{
|
|
var itemDescForm = GameEntry.UI.GetUIForm(UIFormType.ItemDescForm);
|
|
if (itemDescForm != null)
|
|
{
|
|
GameEntry.UI.CloseUIForm(itemDescForm);
|
|
}
|
|
}
|
|
|
|
private RectTransform ResolveDragRoot()
|
|
{
|
|
Canvas canvas = GetComponentInParent<Canvas>();
|
|
if (canvas == null || canvas.rootCanvas == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return canvas.rootCanvas.transform as RectTransform;
|
|
}
|
|
|
|
private bool CreateDragGhost()
|
|
{
|
|
DestroyDragGhost();
|
|
|
|
if (_dragRoot == null || _iconArea == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Sprite iconSprite = _iconArea.CurrentIconSprite;
|
|
if (iconSprite == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
_dragGhostObject = new GameObject("RepoItemDragGhost", typeof(RectTransform), typeof(CanvasGroup), typeof(Image));
|
|
_dragGhostObject.layer = gameObject.layer;
|
|
|
|
_dragGhostRect = _dragGhostObject.GetComponent<RectTransform>();
|
|
_dragGhostRect.SetParent(_dragRoot, false);
|
|
_dragGhostRect.anchorMin = new Vector2(0.5f, 0.5f);
|
|
_dragGhostRect.anchorMax = new Vector2(0.5f, 0.5f);
|
|
_dragGhostRect.pivot = new Vector2(0.5f, 0.5f);
|
|
|
|
Vector2 iconSize = _iconArea.CurrentIconSize;
|
|
if (iconSize.x <= 0f || iconSize.y <= 0f)
|
|
{
|
|
iconSize = DefaultDragGhostSize;
|
|
}
|
|
_dragGhostRect.sizeDelta = iconSize;
|
|
|
|
Image ghostImage = _dragGhostObject.GetComponent<Image>();
|
|
ghostImage.raycastTarget = false;
|
|
ghostImage.sprite = iconSprite;
|
|
ghostImage.color = _iconArea.CurrentIconColor;
|
|
ghostImage.material = _iconArea.CurrentIconMaterial;
|
|
ghostImage.preserveAspect = true;
|
|
|
|
CanvasGroup ghostCanvasGroup = _dragGhostObject.GetComponent<CanvasGroup>();
|
|
ghostCanvasGroup.blocksRaycasts = false;
|
|
ghostCanvasGroup.interactable = false;
|
|
|
|
_dragGhostObject.transform.SetAsLastSibling();
|
|
return true;
|
|
}
|
|
|
|
private void UpdateDragGhostPosition(PointerEventData eventData)
|
|
{
|
|
if (_dragGhostRect == null || _dragRoot == null || eventData == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(_dragRoot, eventData.position,
|
|
eventData.pressEventCamera, out Vector2 localPoint))
|
|
{
|
|
_dragGhostRect.anchoredPosition = localPoint;
|
|
}
|
|
}
|
|
|
|
private void DestroyDragGhost()
|
|
{
|
|
if (_dragGhostObject != null)
|
|
{
|
|
Destroy(_dragGhostObject);
|
|
_dragGhostObject = null;
|
|
_dragGhostRect = null;
|
|
}
|
|
}
|
|
|
|
private void ResetDragState()
|
|
{
|
|
_isDragging = false;
|
|
_dropHandled = false;
|
|
_dropAssigned = false;
|
|
_dragRoot = null;
|
|
DestroyDragGhost();
|
|
|
|
if (_canvasGroup != null)
|
|
{
|
|
_canvasGroup.blocksRaycasts = true;
|
|
}
|
|
}
|
|
}
|
|
}
|