Files
Studio/Assets/Scripts/XED/UI/TreeView/CustomScrollRect.cs
2025-02-19 17:24:26 +09:00

203 lines
7.4 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using XED.UI;
namespace XED.Hierarchy
{
public class CustomScrollRect : ScrollRect, IPointerDownHandler, IPointerUpHandler
{
public bool passDragToChildren = true;
public UnityEvent<HierarchyItem, HierarchyItem> setToChildItem;
public UnityEvent<HierarchyItem, HierarchyItem> setToPriorSiblingItem;
public UnityEvent<HierarchyItem, HierarchyItem> setToNextSiblingItem;
//public UnityEvent onSelect;
public UnityEvent<HierarchyItem> onDragBegin;
public UnityEvent<HierarchyItem> onDragAndDrop;
public GameObject itemPopup;
public GameObject menuPopup;
public HierarchyItem sourceItem;
private ScrollItemUI hoverItemUI;
private Coroutine coroutinePendPopup;
public override void OnBeginDrag(PointerEventData eventData)
{
onDragBegin?.Invoke(sourceItem);
if (!passDragToChildren)
{
base.OnBeginDrag(eventData); // Allow default scrolling if needed
}
}
public override void OnDrag(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
if (hoverItemUI != null) hoverItemUI.DeactivateAllHighlights();
ScrollItemUI itemUI = GetTargetItemUI(eventData);
if (itemUI != null)
{
RectTransform itemRect = itemUI.GetComponent<RectTransform>();
Vector2 localPoint;
RectTransformUtility.ScreenPointToLocalPointInRectangle(
itemRect,
eventData.position,
eventData.pressEventCamera,
out localPoint
);
float rectHeight = itemRect.rect.height;
float normalizedY = (localPoint.y + rectHeight / 2) / rectHeight;
if (normalizedY >= 0.8f) // Upper 20%
{
itemUI.ActivateUpperHighlight();
}
else if (normalizedY <= 0.2f) // Lower 20%
{
itemUI.ActivateLowerHighlight();
}
else // Middle 60%
{
itemUI.ActivateMidHighlight();
}
hoverItemUI = itemUI;
}
}
if (!passDragToChildren)
{
base.OnDrag(eventData);
}
}
public override void OnEndDrag(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
if (hoverItemUI != null) hoverItemUI.DeactivateAllHighlights();
if (coroutinePendPopup != null)
{
StopCoroutine(coroutinePendPopup);
coroutinePendPopup = null;
}
itemPopup.SetActive(false);
//Add to Other Item Hierarchy
ScrollItemUI itemUI = GetTargetItemUI(eventData);
if (itemUI != null && sourceItem != null)
{
RectTransform itemRect = itemUI.GetComponent<RectTransform>(); // Get RectTransform of the item
Vector2 localPoint;
// Convert screen position to local position within the item
RectTransformUtility.ScreenPointToLocalPointInRectangle(
itemRect,
eventData.position,
eventData.pressEventCamera,
out localPoint
);
float rectHeight = itemRect.rect.height; // Height of the item's RectTransform
float normalizedY = (localPoint.y + rectHeight / 2) / rectHeight; // Normalize to 0 (bottom) to 1 (top)
hoverItemUI = itemUI;
HierarchyItem destItem = itemUI.currentItem;
if (destItem == null)
return;
if (normalizedY >= 0.8f)
{
setToPriorSiblingItem?.Invoke(sourceItem, destItem);
}
else if (normalizedY <= 0.2f)
{
setToNextSiblingItem?.Invoke(sourceItem, destItem);
}
else
{
setToChildItem?.Invoke(sourceItem, destItem);
}
sourceItem = null;
}
onDragAndDrop?.Invoke(sourceItem);
sourceItem = null;
}
if (!passDragToChildren)
{
base.OnEndDrag(eventData);
}
}
public void OnPointerDown(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
ScrollItemUI itemUI = GetTargetItemUI(eventData);
if (itemUI != null)
{
sourceItem = itemUI.currentItem;
}
if (sourceItem != null)
{
coroutinePendPopup = StartCoroutine(CoroutinePendPopup());
}
}
}
public void OnPointerUp(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left)
{
if (coroutinePendPopup != null)
{
StopCoroutine(coroutinePendPopup);
coroutinePendPopup = null;
}
itemPopup.SetActive(false);
}
else if (eventData.button == PointerEventData.InputButton.Right)
{
if (menuPopup != null)
{
menuPopup.SetActive(true);
}
}
}
private ScrollItemUI GetTargetItemUI(PointerEventData eventData)
{
PointerEventData pointerData = new PointerEventData(EventSystem.current)
{
position = eventData.position // Get mouse position at drag end
};
var results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, results); // Raycast against UI elements
ScrollItemUI itemUI = null;
foreach (var result in results)
{
itemUI = result.gameObject.GetComponent<ScrollItemUI>();
if (itemUI != null) // Exclude the dragged item itself
{
break;
}
}
if (itemUI != null && itemUI.GetComponentInParent<CustomScrollRect>() == this)
return itemUI;
return null;
}
public bool IsPointerOverScrollRect()
{
return RectTransformUtility.RectangleContainsScreenPoint(
GetComponent<RectTransform>(), Input.mousePosition);
}
IEnumerator CoroutinePendPopup()
{
yield return new WaitForSeconds(0.1f);
itemPopup.SetActive(true);
yield return null;
}
}
}