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 setToChildItem; public UnityEvent setToPriorSiblingItem; public UnityEvent setToNextSiblingItem; //public UnityEvent onSelect; public UnityEvent onDragBegin; public UnityEvent 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(); 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(); // 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(); EventSystem.current.RaycastAll(pointerData, results); // Raycast against UI elements ScrollItemUI itemUI = null; foreach (var result in results) { itemUI = result.gameObject.GetComponent(); if (itemUI != null) // Exclude the dragged item itself { break; } } if (itemUI != null && itemUI.GetComponentInParent() == this) return itemUI; return null; } public bool IsPointerOverScrollRect() { return RectTransformUtility.RectangleContainsScreenPoint( GetComponent(), Input.mousePosition); } IEnumerator CoroutinePendPopup() { yield return new WaitForSeconds(0.1f); itemPopup.SetActive(true); yield return null; } } }