버그 수정 중. 이동 후 남겨지는 경우가 있음
This commit is contained in:
@@ -6,23 +6,27 @@ using UnityEngine;
|
||||
namespace UVC.UI.List.Tree
|
||||
{
|
||||
/// <summary>
|
||||
/// 트리 리스트의 드래그 & 드롭 기능을 관리하는 클래스입니다.
|
||||
/// 트리 리스트의 드래그 & 드롭 상호작용을 상태와 이벤트로 중재하는 관리자입니다.
|
||||
///
|
||||
/// 역할:
|
||||
/// 1. 드래그 시작/진행/종료 상태 관리
|
||||
/// 2. 유효한 드롭 대상 판단 (순환 참조 방지)
|
||||
/// 3. 아이템 위치 변경 (형제 아이템 간 순서 변경)
|
||||
/// 4. 아이템 계층 구조 변경 (부모-자식 관계 수정)
|
||||
/// - 드래그 시작/진행/종료 상태 관리(상태 머신)
|
||||
/// - 드롭 유효성 검사(자기 자신/조상에게 드롭 금지로 순환 참조 방지)
|
||||
/// - 구독자에게 이벤트로 진행 상황 전달
|
||||
///
|
||||
/// 기능:
|
||||
/// - 드래그할 아이템과 드롭 대상을 추적
|
||||
/// - 유효성 검사 (자기 자신에게 드롭 금지, 순환 참조 방지)
|
||||
/// - 드롭 완료 후 데이터 동기화
|
||||
/// 책임 경계:
|
||||
/// - 이 매니저는 데이터를 직접 수정(이동/부모 변경)하지 않습니다.
|
||||
/// - 실제 아이템 재배치/재귀 로직은 이벤트 구독자(예: 리스트/뷰 모델)에서 수행해야 합니다.
|
||||
///
|
||||
/// 이벤트 흐름:
|
||||
/// - StartDrag → OnDragStarted(once)
|
||||
/// - OnDragOver → OnDragEntered(repeat, hover 대상에 따라 여러 번)
|
||||
/// - TryDrop 유효 시 → OnDropped → EndDrag → OnDragEnded
|
||||
/// - TryDrop 무효/취소 시 → EndDrag → OnDragEnded
|
||||
/// </summary>
|
||||
public class TreeListDragDropManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 드래그 중인 아이템의 데이터입니다.
|
||||
/// 현재 드래그 중인 아이템입니다(드래그 중이 아니면 null).
|
||||
/// </summary>
|
||||
public TreeListItemData? DraggedItem { get; private set; }
|
||||
|
||||
@@ -32,29 +36,45 @@ namespace UVC.UI.List.Tree
|
||||
public bool IsDragging { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 드래그 시작 시 발생하는 이벤트입니다.
|
||||
/// 드래그 시작 시 1회 발생하는 이벤트입니다.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 핸들러 시그니처: (TreeListItemData dragged)
|
||||
/// </remarks>
|
||||
public Action<TreeListItemData>? OnDragStarted;
|
||||
|
||||
/// <summary>
|
||||
/// 드래그 진행 중 발생하는 이벤트입니다.
|
||||
/// 드래그 진행 중 마우스가 특정 아이템 위에 있을 때 반복적으로 발생하는 이벤트입니다.
|
||||
/// 빈 공간 위라면 <c>targetItem</c>은 null이 될 수 있습니다.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 핸들러 시그니처: (TreeListItemData dragged, TreeListItemData? targetItem)
|
||||
/// 이벤트 발생 빈도가 높으므로, 처리 로직은 가볍게 유지하세요.
|
||||
/// </remarks>
|
||||
public Action<TreeListItemData, TreeListItemData?>? OnDragEntered;
|
||||
|
||||
/// <summary>
|
||||
/// 드래그 종료 시 발생하는 이벤트입니다.
|
||||
/// 드래그가 종료될 때 발생하는 이벤트입니다(드롭 성공/실패/취소 포함).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 핸들러 시그니처: (TreeListItemData dragged)<br/>
|
||||
/// 드롭 성공 시에는 OnDropped 이후에 호출됩니다.
|
||||
/// </remarks>
|
||||
public Action<TreeListItemData>? OnDragEnded;
|
||||
|
||||
/// <summary>
|
||||
/// 드롭 완료 시 발생하는 이벤트입니다.
|
||||
/// 유효성 검사를 통과한 드롭이 확정될 때 발생하는 이벤트입니다.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 핸들러 시그니처: (TreeListItemData dragged, TreeListItemData? target)<br/>
|
||||
/// 이 이벤트에서 실제 데이터 구조 변경(이동/부모 변경/정렬)을 수행하세요.
|
||||
/// </remarks>
|
||||
public Action<TreeListItemData, TreeListItemData?>? OnDropped;
|
||||
|
||||
/// <summary>
|
||||
/// 드래그를 시작합니다.
|
||||
/// 드래그를 시작합니다. 이미 드래그 중이면 무시됩니다.
|
||||
/// </summary>
|
||||
/// <param name="draggedItem">드래그할 아이템</param>
|
||||
/// <param name="draggedItem">드래그할 아이템.</param>
|
||||
public void StartDrag(TreeListItemData draggedItem)
|
||||
{
|
||||
if (IsDragging)
|
||||
@@ -69,9 +89,10 @@ namespace UVC.UI.List.Tree
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 드래그 중에 마우스가 다른 아이템 위에 있을 때 호출됩니다.
|
||||
/// 드래그 중 마우스가 다른 아이템(또는 빈 영역) 위에 있을 때 호출됩니다.
|
||||
/// 상태를 변경하지 않고, 단순히 현재 hover 대상을 이벤트로 통지합니다.
|
||||
/// </summary>
|
||||
/// <param name="targetItem">현재 마우스 위에 있는 아이템</param>
|
||||
/// <param name="targetItem">현재 마우스 아래의 아이템. 빈 공간이면 null.</param>
|
||||
public void OnDragOver(TreeListItemData? targetItem)
|
||||
{
|
||||
if (!IsDragging || DraggedItem == null)
|
||||
@@ -83,7 +104,7 @@ namespace UVC.UI.List.Tree
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 드래그를 종료합니다.
|
||||
/// 드래그를 종료합니다. 드래그 중이 아니면 아무 동작도 하지 않습니다.
|
||||
/// </summary>
|
||||
public void EndDrag()
|
||||
{
|
||||
@@ -99,11 +120,19 @@ namespace UVC.UI.List.Tree
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 드래그된 아이템을 대상 아이템에 드롭합니다.
|
||||
/// 드래그된 아이템을 대상 아이템에 드롭 시도합니다.
|
||||
/// 유효성 검사(자기 자신/조상에게 드롭 금지)를 통과한 경우에만 OnDropped를 발생시킵니다.
|
||||
/// </summary>
|
||||
/// <param name="targetItem">드롭 대상 아이템 (null이면 루트 레벨)</param>
|
||||
/// <param name="insertIndex">대상 부모 내에서의 삽입 위치 (-1이면 끝에 추가)</param>
|
||||
/// <returns>드롭 성공 여부</returns>
|
||||
/// <param name="targetItem">드롭 대상 아이템. 루트 레벨로 드롭하려면 null.</param>
|
||||
/// <param name="insertIndex">
|
||||
/// 대상 부모 내 삽입 위치. -1이면 끝에 추가 의도.
|
||||
/// 현재 구현에서는 이 값이 내부에서 사용되지 않으며, 필요 시 이벤트 모델 확장이 필요합니다.
|
||||
/// </param>
|
||||
/// <returns>드롭을 성공적으로 수락하여 이벤트를 발생시켰으면 true, 그 외는 false.</returns>
|
||||
/// <remarks>
|
||||
/// 성공 시 순서: OnDropped(once) → EndDrag → OnDragEnded.<br/>
|
||||
/// 실패/무효 시: EndDrag → OnDragEnded.
|
||||
/// </remarks>
|
||||
public bool TryDrop(TreeListItemData? targetItem, int insertIndex = -1)
|
||||
{
|
||||
if (!IsDragging || DraggedItem == null)
|
||||
@@ -125,6 +154,7 @@ namespace UVC.UI.List.Tree
|
||||
return false;
|
||||
}
|
||||
|
||||
// 주의: insertIndex는 현재 이벤트로 전달되지 않습니다(모델 확장 필요).
|
||||
OnDropped?.Invoke(DraggedItem, targetItem);
|
||||
|
||||
EndDrag();
|
||||
@@ -133,11 +163,13 @@ namespace UVC.UI.List.Tree
|
||||
|
||||
/// <summary>
|
||||
/// 첫 번째 아이템이 두 번째 아이템의 조상인지 확인합니다.
|
||||
/// 순환 참조를 방지하기 위해 사용됩니다.
|
||||
/// </summary>
|
||||
/// <param name="potentialAncestor">조상일 가능성이 있는 아이템</param>
|
||||
/// <param name="potentialDescendant">후손일 가능성이 있는 아이템</param>
|
||||
/// <returns>조상-후손 관계이면 true</returns>
|
||||
/// <param name="potentialAncestor">조상일 가능성이 있는 아이템.</param>
|
||||
/// <param name="potentialDescendant">후손일 가능성이 있는 아이템.</param>
|
||||
/// <returns>조상-후손 관계이면 true, 아니면 false.</returns>
|
||||
/// <remarks>
|
||||
/// 상향 탐색으로 O(h) 시간 복잡도입니다(h: 트리 높이).
|
||||
/// </remarks>
|
||||
public static bool IsAncestorOf(TreeListItemData potentialAncestor, TreeListItemData potentialDescendant)
|
||||
{
|
||||
var current = potentialDescendant.Parent;
|
||||
@@ -157,7 +189,7 @@ namespace UVC.UI.List.Tree
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 모든 드래그 & 드롭 상태를 리셋합니다.
|
||||
/// 드래그 & 드롭 상태를 초기화합니다.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user