
저번에 구한 Path 들을 에디터에 Treeview로 나타내고, Checkbox를 통해 지울 대상을 선택할 수 있도록 하겠습니다.
Unity Document 에 보면 TreeView라는 클래스를 상속받아서 구현할 수 있습니다.
해당 클래스를 통해 아래와 같은 TreeView를 구현해보겠습니다.

TreeView의 각 아이템은 TreeViewItem 으로 구성되며, 해당 클래스에는 아이디, 부모, 자식, 깊이, 이름, 아이콘 등을 설정할 수 있습니다.

하지만 TreeView의 정적함수 중 SetupDepthsFromParentsAndChildren 이라는 함수를 사용하면 Depth는 계산해주므로, 저희는 Id, parent, children, displayName을 신경써야 합니다.
경로가 들어오면, Split 함수를 통해 '/' 단위로 나누고 루트에서부터 폴더를 만들거나 부모를 설정해주어야합니다.
protected override TreeViewItem BuildRoot()
{
var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" };
int id = 1;
foreach (var asset in assets)
{
var pathParts = asset.Split('/');
TreeViewItem currentParent = root;
for (int i = 0; i < pathParts.Length; i++)
{
string pathPart = pathParts[i];
TreeViewItem existingChild = currentParent.children?.Find(child => child.displayName == pathPart);
if (existingChild == null) // 일치하는 이름 없으면 폴더 (혹은 파일) 만들기
{
var newChild = new TreeViewItem { id = id++, displayName = pathPart, parent = currentParent };
if (currentParent.children == null)
currentParent.children = new List<TreeViewItem>();
currentParent.children.Add(newChild);
currentParent = newChild;
}
else // 있으면 부모로 설정하고 다음 경로 탐색
{
currentParent = existingChild;
}
}
}
SetupDepthsFromParentsAndChildren(root); // Depth 자동설정
return root;
}
추상함수인 BuildRoot 입니다.
Root로부터 모든 경로의 각 폴더, 파일들을 Item으로 만들어서 Parent-Child 관계를 만들어줍니다.

여기까지의 실행결과입니다.
제 목표는 Checkbox를 통해 지울 에셋들을 선택하는 것입니다.
각 Item의 GUI를 변경하기 위해서는 RowGUI 함수를 사용하면 됩니다. (참고)
Override this method to add custom GUI content for the rows in the TreeView.
각 TreeView의 Row GUI content 를 custom 할때 override 하라고 합니다.
protected override void RowGUI(RowGUIArgs args)
{
}
base.RowGUI(args) 를 호출하면 위의 사진과 같이 일반적인 텍스트 트리뷰가 나오고, 아무것도 적지않으면 아래와같이 나옵니다.

저희가 하고싶은건 저 토글버튼과 TreeViewItem 의 이름 사이에 Checkbox를 넣는 것이기 때문에, base.RowGUI(args) 호출 전에 Checkbox를 그려주면 될 것 같습니다.
protected override void RowGUI(RowGUIArgs args)
{
Rect checkBoxRect = new Rect(args.rowRect.x + GetContentIndent(args.item), args.rowRect.y, 2, args.rowRect.height);
bool newToggled = EditorGUI.Toggle(checkBoxRect, true);
base.RowGUI(args);
}

하지만 base.RowGUI 도 Indent 만 고려하여 만들어졌기 때문에 checkbox와 라벨이 겹치게됩니다.
해당 부분은 base.RowGUI 를 호출할때 넘기는 args를 수정하여 고칠 수 있습니다.
protected override void RowGUI(RowGUIArgs args)
{
Rect toggleRect = new Rect(args.rowRect.x, args.rowRect.y, GetContentIndent(args.item), args.rowRect.height);
base.RowGUI(new RowGUIArgs
{
rowRect = args.rowRect,
item = args.item,
label = "", // Label을 아래에서 따로 작성
selected = args.selected,
focused = args.focused
});
Rect checkBoxRect = new Rect(toggleRect.xMax + 2, args.rowRect.y, 20, args.rowRect.height);
bool isToggled = toggledItemIds.Contains(args.item.id);
bool newToggled = EditorGUI.Toggle(checkBoxRect, isToggled);
Rect nameRect = new Rect(checkBoxRect.xMax + 5, args.rowRect.y, args.rowRect.width - checkBoxRect.xMax - 5, args.rowRect.height);
EditorGUI.LabelField(nameRect, args.item.displayName);
}


다음은 편의성을 위한 Checkbox 기능을 추가해야 합니다.
Package manager를 통해 에셋을 임포트 해봤다면 아시겠지만, 부모 아이템의 체크박스를 해제, 선택하면 자식들도 전부 해제/선택 됩니다.
또한, 자식이 하나라도 체크되면 부모도 체크, 아무도 체크되어있지 않으면 부모도 체크해제 되도록 해야합니다.
private void CheckAllItems(TreeViewItem item, bool isChecked)
{
if (isChecked)
toggledItemIds.Add(item.id);
else
toggledItemIds.Remove(item.id);
if (item.children != null)
{
foreach (var child in item.children)
{
CheckAllItems(child, isChecked);
}
}
}
체크하면 해당 아이템과 그 자식들 전부 체크/해제 시켜주는 함수입니다.
toggledItemIds 는 토글된 아이템들을 저장하는 HashSet 입니다.
(Paths에는 폴더가 포함되지 않고, TreeViewItem 들은 폴더가 있기 때문에 따로 저장해야합니다.)
자식은 완료되었으니 부모만 신경써주면 됩니다.
private void UpdateParentItems(TreeViewItem item, bool isChecked)
{
if (item.parent == null)
return;
if (isChecked)
{
bool allChildrenChecked = item.parent.children.
TrueForAll(child => toggledItemIds.Contains(child.id));
if (allChildrenChecked)
toggledItemIds.Add(item.parent.id);
}
else
{
toggledItemIds.Remove(item.parent.id);
}
UpdateParentItems(item.parent, isChecked);
}

TreeView 를 상속받고 BuildRoot 와 RowGUI 함수를 오버라이드 하여 원하는 TreeView Editor를 만들었습니다.
하지만, 모두 선택하면 Assets 폴더까지 선택되는 특성 때문에 폴더는 지우지못하고 있습니다.
따라서 다음에는 빈 폴더를 모두 삭제하는 옵션을 추가하고, Config 를 Editor에서 실시간으로 수정가능하도록 만들어보겠습니다.
https://docs.unity3d.com/kr/2018.4/ScriptReference/IMGUI.Controls.TreeView.html