This commit is contained in:
logonkhi
2025-11-14 17:02:38 +09:00
parent c98c1d9d9a
commit 934fff54a7
13 changed files with 579 additions and 162 deletions

View File

@@ -530,6 +530,17 @@ namespace UVC.UI.List.Tree
UpdateFlattenedItemDataList();
}
/// <summary>
/// TreeListItem 프리팹 인스턴스화
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T? Create<T>() where T : TreeListItem
{
T? item = GameObject.Instantiate(ItemPrefab, root) as T;
return item;
}
/// <summary>
/// 새 아이템 추가
///
@@ -548,11 +559,11 @@ namespace UVC.UI.List.Tree
data.Parent = null;
// Instantiate(템플릿, 부모 Transform)
// = 템플릿을 복제하고 부모의 자식으로 설정
T item = GameObject.Instantiate(ItemPrefab, root) as T;
T? item = Create<T>();
// 생성된 아이템 초기화
// 데이터를 UI에 바인딩하고 이벤트 리스너 등록
item.Init(data, this, dragDropManager);
item?.Init(data, this, dragDropManager);
items.Add(data);
// 범위 선택에 필요한 평탄화 리스트 업데이트
@@ -560,6 +571,27 @@ namespace UVC.UI.List.Tree
}
/// <summary>
/// 새 아이템들 추가
/// </summary>
/// <typeparam name="T">추가 할 타입</typeparam>
/// <param name="datas">추가 할 데이터들</param>
public void AddItems<T>(IEnumerable<TreeListItemData> datas) where T : TreeListItem
{
foreach (var data in datas)
{
data.Parent = null;
// Instantiate(템플릿, 부모 Transform)
// = 템플릿을 복제하고 부모의 자식으로 설정
T? item = Create<T>();
// 생성된 아이템 초기화
// 데이터를 UI에 바인딩하고 이벤트 리스너 등록
item?.Init(data, this, dragDropManager);
items.Add(data);
}
UpdateFlattenedItemDataList();
}
/// <summary>
/// 지정 인덱스에 아이템 추가
///
@@ -970,6 +1002,19 @@ namespace UVC.UI.List.Tree
OnItemSelectionChanged?.Invoke(data, true);
}
/// <summary>
/// 이름으로 아이템 선택 해제
/// </summary>
/// <param name="name"></param>
public void DeselectItem(string name)
{
var item = allItemDataFlattened.FirstOrDefault(x => x.Name == name);
if (item != null)
{
DeselectItem(item);
}
}
/// <summary>
/// 아이템 선택 해제
///

View File

@@ -72,6 +72,12 @@ namespace UVC.UI.List.Tree
[SerializeField]
protected Button itemButton;
/// <summary>
/// text가 배치 된 RectTransform.
/// </summary>
[SerializeField]
protected RectTransform layout;
#endregion
#region (Data Fields)
@@ -91,6 +97,8 @@ namespace UVC.UI.List.Tree
/// </summary>
protected bool isAnimating = false;
protected VerticalLayoutGroup? childRootLayoutGroup = null;
#endregion
#region (Initialization)
@@ -123,7 +131,12 @@ namespace UVC.UI.List.Tree
valueText.text = data.Name;
// 3. 자식 아이템들을 UI로 생성
Debug.Log("Creating Children for " + data.Name + ", " + data.Children.Count);
//Debug.Log("Creating Children for " + data.Name + ", " + data.Children.Count);
if (childRootLayoutGroup == null)
{
childRootLayoutGroup = childRoot.GetComponent<VerticalLayoutGroup>();
}
if (data.Children.Count > 0)
@@ -164,7 +177,7 @@ namespace UVC.UI.List.Tree
if (dragHandler == null)
{
dragHandler = gameObject.AddComponent<TreeListItemDragHandler>();
Debug.Log($"[TreeListItem.Init] 새로운 TreeListItemDragHandler 추가: {data.Name}");
//Debug.Log($"[TreeListItem.Init] 새로운 TreeListItemDragHandler 추가: {data.Name}");
}
dragHandler.SetDragDropManager(this, control, dragDropManager);
@@ -173,7 +186,7 @@ namespace UVC.UI.List.Tree
// Register view to map
treeList.RegisterView(data, this);
Debug.Log($"[TreeListItem.Init] 초기화 완료: {data.Name}");
//Debug.Log($"[TreeListItem.Init] 초기화 완료: {data.Name}");
}
#endregion
@@ -305,7 +318,7 @@ namespace UVC.UI.List.Tree
else if (changedType == ChangedType.RemoveChild)
{
//따로 할것 없음 - 펼침 버튼 갱신 용
Debug.Log($"RemoveChild 처리 완료 {changedData.Name}, {index}");
//Debug.Log($"RemoveChild 처리 완료 {changedData.Name}, {index}");
}
UniTask.DelayFrame(1).ContinueWith(() =>
@@ -539,6 +552,12 @@ namespace UVC.UI.List.Tree
treeList.ItemPrefab, // 복제할 프리팹
childRoot // 부모로 배치할 위치
);
//item.layout의 너비를 childRootLayoutGroup의 padding.left 만큼 줄이기
if (item != null && item.layout != null && childRootLayoutGroup != null)
{
item.layout.sizeDelta = new Vector2(layout.sizeDelta.x - childRootLayoutGroup.padding.left, item.layout.sizeDelta.y);
}
// 2. 생성된 아이템 초기화
item.Init(data, treeList, treeList.DragDropManager);

View File

@@ -92,12 +92,11 @@ namespace UVC.UI.List.Tree
treeList = list;
dragDropManager = manager;
treeListRootParent = list.Root.parent as RectTransform;
Debug.Log($"[TreeListItemDragHandler] 드래그 핸들러 설정: {item.Data?.Name ?? "Unknown"}");
//Debug.Log($"[TreeListItemDragHandler] 드래그 핸들러 설정: {item.Data?.Name ?? "Unknown"}");
}
public void OnBeginDrag(PointerEventData eventData)
{
Debug.Log("[OnPointerDown]");
if (!enableDragDrop || treeListItem?.Data == null || dragDropManager == null)
{
return;
@@ -117,7 +116,7 @@ namespace UVC.UI.List.Tree
dragOffset = localPoint;
_lastPointerScreenPos = eventData.position;
Debug.Log($"[OnPointerDown] {treeListItem.Data.Name}에 포인터 다운, offset: {dragOffset}");
//Debug.Log($"[OnPointerDown] {treeListItem.Data.Name}에 포인터 다운, offset: {dragOffset}");
}
public void OnDrag(PointerEventData eventData)
@@ -134,7 +133,7 @@ namespace UVC.UI.List.Tree
}
_lastPointerScreenPos = eventData.position;
Debug.Log($"[OnDrag] {treeListItem.Data.Name} 드래그 중");
//Debug.Log($"[OnDrag] {treeListItem.Data.Name} 드래그 중");
if (!dragDropManager.IsDragging)
{
@@ -151,7 +150,7 @@ namespace UVC.UI.List.Tree
CreateDropIndicator();
Debug.Log($"[OnDrag] {treeListItem.Data.Name} 드래그 시작");
//Debug.Log($"[OnDrag] {treeListItem.Data.Name} 드래그 시작");
}
// 마우스 위의 드롭 대상 찾기
@@ -191,13 +190,12 @@ namespace UVC.UI.List.Tree
public void OnEndDrag(PointerEventData eventData)
{
Debug.Log("[OnPointerUp]");
if (!enableDragDrop || dragDropManager == null)
{
return;
}
Debug.Log("[OnPointerUp] 드래그 완료");
//Debug.Log("[OnPointerUp] 드래그 완료");
if (canvasGroup != null)
{
@@ -228,7 +226,7 @@ namespace UVC.UI.List.Tree
if (treeListItem?.Data != null)
{
var result = dragDropManager.TryDrop(targetItem?.Data);
Debug.Log($"[OnPointerUp] 드롭 결과: {(result ? "" : "")}");
//Debug.Log($"[OnPointerUp] 드롭 결과: {(result ? "성공" : "실패")}");
if (result) HandleDropSuccess(treeListItem.Data, targetItem);
}
@@ -305,7 +303,6 @@ namespace UVC.UI.List.Tree
private void CreateDropIndicator()
{
Debug.Log($"[CreateDropIndicator] dropIndicator != null:{dropIndicator != null}");
if (dropIndicator != null)
{
return;
@@ -318,7 +315,7 @@ namespace UVC.UI.List.Tree
dropIndicatorRect = existingDropIndicator.GetComponent<RectTransform>();
dropIndicatorParent = treeListRootParent;
Debug.Log("[CreateDropIndicator] 기존 DropIndicator를 재사용합니다");
//Debug.Log("[CreateDropIndicator] 기존 DropIndicator를 재사용합니다");
return;
}
@@ -348,7 +345,7 @@ namespace UVC.UI.List.Tree
dropIndicator.raycastTarget = false;
indicatorGo.SetActive(false);
Debug.Log("[CreateDropIndicator] 드롭 위치 표시 막대 생성됨");
//Debug.Log("[CreateDropIndicator] 드롭 위치 표시 막대 생성됨");
}
private void UpdateDropIndicator(TreeListItem? targetItem)
@@ -422,7 +419,7 @@ namespace UVC.UI.List.Tree
dropIndicatorRect.anchoredPosition = new Vector2(indicatorX, indicatorY);
dropIndicatorRect.sizeDelta = new Vector2(dropIndicatorRect.sizeDelta.x, indicatorHeight);
Debug.Log($"[UpdateDropIndicator] {targetItem?.Data?.Name} 위치: {dropPosition}, targetY: {targetWorldY}, parentY: {parentWorldY}, indicatorY: {indicatorY}");
//Debug.Log($"[UpdateDropIndicator] {targetItem?.Data?.Name} 위치: {dropPosition}, targetY: {targetWorldY}, parentY: {parentWorldY}, indicatorY: {indicatorY}");
}
private void HideDropIndicator()
@@ -446,12 +443,10 @@ namespace UVC.UI.List.Tree
Transform child = treeListRootParent.GetChild(i);
if (child.name == "DropIndicator")
{
Debug.Log("[FindDropIndicatorInRoot] DropIndicator를 찾았습니다");
return child.gameObject;
}
}
Debug.Log("[FindDropIndicatorInRoot] DropIndicator를 찾지 못했습니다");
return null;
}
@@ -476,7 +471,7 @@ namespace UVC.UI.List.Tree
es.RaycastAll(eventData, s_RaycastResults);
Debug.Log($"[GetItemAtMousePosition] Raycast 결과: {s_RaycastResults.Count}개");
//Debug.Log($"[GetItemAtMousePosition] Raycast 결과: {s_RaycastResults.Count}개");
for (int i = 0; i < s_RaycastResults.Count; i++)
{
@@ -484,7 +479,7 @@ namespace UVC.UI.List.Tree
var item = result.gameObject.GetComponentInParent<TreeListItem>();
if (item != null)
{
Debug.Log($"[GetItemAtMousePosition] 찾은 아이템: {item.Data?.Name ?? "Unknown"}");
//Debug.Log($"[GetItemAtMousePosition] 찾은 아이템: {item.Data?.Name ?? "Unknown"}");
return item;
}
}
@@ -501,7 +496,6 @@ namespace UVC.UI.List.Tree
if (targetItem == null)
{
Debug.Log("[HandleDropSuccess] 루트로 이동");
MoveToRoot(draggedData);
treeList.ScheduleFlattenedUpdate();
return;
@@ -515,7 +509,7 @@ namespace UVC.UI.List.Tree
var dropPosition = GetDropPosition(targetItem.GetComponent<RectTransform>());
Debug.Log($"[HandleDropSuccess] 드롭 위치: {targetItem?.Data?.Name} {dropPosition}");
//Debug.Log($"[HandleDropSuccess] 드롭 위치: {targetItem?.Data?.Name} {dropPosition}");
switch (dropPosition)
{
@@ -561,7 +555,7 @@ namespace UVC.UI.List.Tree
private void MoveToRoot(TreeListItemData draggedData)
{
Debug.Log($"[MoveToRoot] {draggedData.Name}을(를) 루트로 이동");
//Debug.Log($"[MoveToRoot] {draggedData.Name}을(를) 루트로 이동");
if (treeList == null)
{
@@ -583,13 +577,13 @@ namespace UVC.UI.List.Tree
{
treeList.AddCloneItem(draggedData);
}
Debug.Log($"[MoveToRoot] {draggedData.Name}을(를) 루트 레벨의 끝에 추가");
//Debug.Log($"[MoveToRoot] {draggedData.Name}을(를) 루트 레벨의 끝에 추가");
}
private void MoveAsChild(TreeListItemData draggedData, TreeListItemData targetData)
{
targetData.AddCloneChild(draggedData);
Debug.Log($"[MoveAsChild] {draggedData.Name}을(를) {targetData.Name}의 자식으로 이동");
//Debug.Log($"[MoveAsChild] {draggedData.Name}을(를) {targetData.Name}의 자식으로 이동");
}
private void MoveBefore(TreeListItemData draggedData, TreeListItemData targetData)
@@ -604,7 +598,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
draggedData.Parent.SwapChild(draggedData, targetIndex);
Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 순서 변경");
//Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 순서 변경");
}
}
else
@@ -617,7 +611,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
treeList?.SwapItem(draggedData, targetIndex);
Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 순서 변경(루트레벨)");
//Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 순서 변경(루트레벨)");
}
}
}
@@ -631,7 +625,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
parentData.AddCloneAtChild(draggedData, targetIndex);
Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 이동");
//Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 이동");
}
}
else
@@ -643,7 +637,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
treeList?.AddCloneItemAt(draggedData, targetIndex);
Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 이동 (루트 레벨)");
//Debug.Log($"[MoveBefore] {draggedData.Name}을(를) {targetData.Name} 앞으로 {targetIndex} 이동 (루트 레벨)");
}
}
}
@@ -662,7 +656,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
draggedData.Parent.SwapChild(draggedData, targetIndex + 1);
Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 순서 변경");
//Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 순서 변경");
}
}
else
@@ -675,7 +669,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
treeList?.SwapItem(draggedData, targetIndex + 1);
Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 순서 변경(루트레벨)");
//Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 순서 변경(루트레벨)");
}
}
}
@@ -690,7 +684,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
parentData.AddCloneAtChild(draggedData, targetIndex + 1);
Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 이동");
//Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 이동");
}
}
else
@@ -702,7 +696,7 @@ namespace UVC.UI.List.Tree
if (targetIndex >= 0)
{
treeList?.AddCloneItemAt(draggedData, targetIndex + 1);
Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 이동 (루트 레벨)");
//Debug.Log($"[MoveAfter] {draggedData.Name}을(를) {targetData.Name} 뒤로 {targetIndex} 이동 (루트 레벨)");
}
}
}

View File

@@ -132,6 +132,15 @@ namespace UVC.UI.Window
treeList.AddItem<TreeListItem>(data);
}
/// <summary>
/// 메인 트리에 항목들을 추가합니다.
/// </summary>
/// <param name="dataList">추가 할 데이터들</param>
public void AddItems(System.Collections.Generic.IEnumerable<TreeListItemData> dataList)
{
treeList.AddItems<TreeListItem>(dataList);
}
/// <summary>
/// 메인 트리에 항목을 특정 인덱스에 삽입합니다.
/// </summary>
@@ -175,6 +184,15 @@ namespace UVC.UI.Window
treeList.SelectItem(name);
}
/// <summary>
/// 이름으로 아이템 선택 해제
/// </summary>
/// <param name="name"></param>
public void DeselectItem(string name)
{
treeList.DeselectItem(name);
}
protected void StartLoadingAnimation()
{
if (loadingImage == null) return;