2022-01-16 05:40:49 +03:00

302 lines
11 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using HeurekaGames.AssetHunterPRO.BaseTreeviewImpl.AssetTreeView;
using UnityEngine;
using UnityEditor;
using System.Linq;
using HeurekaGames.AssetHunterPRO.BaseTreeviewImpl;
using System.IO;
namespace HeurekaGames.AssetHunterPRO
{
[System.Serializable]
public class AH_TreeViewSelectionInfo
{
public delegate void AssetDeletedHandler();
public static event AssetDeletedHandler OnAssetDeleted;
private bool hasSelection;
public bool HasSelection
{
get
{
return hasSelection;
}
}
public const float Height = 64;
private AH_MultiColumnHeader multiColumnHeader;
private List<AH_TreeviewElement> selection;
internal void Reset()
{
selection = null;
hasSelection = false;
}
internal void SetSelection(AH_TreeViewWithTreeModel treeview, IList<int> selectedIds)
{
multiColumnHeader = (AH_MultiColumnHeader)(treeview.multiColumnHeader);
selection = new List<AH_TreeviewElement>();
foreach (var itemID in selectedIds)
{
selection.Add(treeview.treeModel.Find(itemID));
}
hasSelection = (selection.Count > 0);
//If we have more, select the assets in project view
if (hasSelection)
{
if (selection.Count > 1)
{
UnityEngine.Object[] selectedObjects = new UnityEngine.Object[selection.Count];
for (int i = 0; i < selection.Count; i++)
{
selectedObjects[i] = AssetDatabase.LoadMainAssetAtPath(selection[i].RelativePath);
}
Selection.objects = selectedObjects;
}
else
Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(selection[0].RelativePath);
AH_Utils.PingObjectAtPath(selection[selection.Count - 1].RelativePath, false);
}
}
internal void OnGUISelectionInfo(Rect selectionRect)
{
GUILayout.BeginArea(selectionRect);
//TODO MAKE SURE WE DONT DO ALL OF THIS EACH FRAME, BUT CACHE THE SELECTION DATA
using (new EditorGUILayout.HorizontalScope())
{
if (selection.Count == 1)
{
drawSingle();
}
else
{
drawMulti();
}
}
GUILayout.EndArea();
}
private void drawSingle()
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.BeginVertical();
drawAssetPreview(true);
EditorGUILayout.EndVertical();
//Draw info from single asset
EditorGUILayout.BeginVertical();
GUILayout.Label(selection[0].RelativePath);
if (!selection[0].IsFolder)
{
GUILayout.Label("(" + selection[0].AssetType + ")");
}
EditorGUILayout.EndVertical();
GUILayout.FlexibleSpace();
if (selection[0].IsFolder)
DrawDeleteFolderButton(selection[0]);
else
drawDeleteAssetsButton();
EditorGUILayout.EndHorizontal();
}
private void drawMulti()
{
//Make sure we have not selected folders
bool allFolders = selection.All(val => val.IsFolder);
bool allFiles = !selection.Any(val => val.IsFolder);
var allSameType = selection.All(var => var.AssetType == selection[0].AssetType);
//Find if we have selected nested assets or folders
var containsNested = selection.Any(file => selection.Any(y => file != y && (y.RelativePath.StartsWith(file.RelativePath) && y.RelativePath.Split(Path.DirectorySeparatorChar).Length != file.RelativePath.Split(Path.DirectorySeparatorChar).Length)));
drawAssetPreview(allSameType);
EditorGUILayout.BeginHorizontal();
//Draw info from multiple
EditorGUILayout.BeginVertical();
//Identical files
if (allSameType && allFiles)
{
GUILayout.Label(selection[0].AssetType.ToString() + " (" + selection.Count() + ")");
}
//all folders
else if (allSameType)
{
GUILayout.Label("Folders (" + selection.Count() + ")");
}
//Non identical selection
else
{
GUILayout.Label("Items (" + selection.Count() + ")");
}
EditorGUILayout.EndVertical();
if (!containsNested)
drawDeleteAssetsButton();
EditorGUILayout.EndHorizontal();
}
private void drawDeleteAssetsButton()
{
if (multiColumnHeader.ShowMode != AH_MultiColumnHeader.AssetShowMode.Unused)
return;
long combinedSize = 0;
foreach (var item in selection)
{
if (item.IsFolder)
combinedSize += item.GetFileSizeRecursively(AH_MultiColumnHeader.AssetShowMode.Unused);
else
combinedSize += item.FileSize;
}
if (GUILayout.Button("Delete " + (AH_Utils.GetSizeAsString(combinedSize)), GUILayout.Width(160), GUILayout.Height(32)))
deleteUnusedAssets();
}
private void DrawDeleteFolderButton(AH_TreeviewElement folder)
{
if (multiColumnHeader.ShowMode != AH_MultiColumnHeader.AssetShowMode.Unused)
return;
string description = "Delete unused assets from folder";
GUIContent content = new GUIContent("Delete " + (AH_Utils.GetSizeAsString(folder.GetFileSizeRecursively(AH_MultiColumnHeader.AssetShowMode.Unused))), description);
GUIStyle style = new GUIStyle(GUI.skin.button);
DrawDeleteFolderButton(content, folder, style, description, "Do you want to delete all unused assets from:" + Environment.NewLine + folder.RelativePath, GUILayout.Width(160), GUILayout.Height(32));
}
public void DrawDeleteFolderButton(GUIContent content, AH_TreeviewElement folder, GUIStyle style, string dialogHeader, string dialogDescription, params GUILayoutOption[] layout)
{
if (GUILayout.Button(content, style, layout))
deleteUnusedFromFolder(dialogHeader, dialogDescription, folder);
}
private void drawAssetPreview(bool bDraw)
{
GUIContent content = new GUIContent();
//Draw asset preview
if (bDraw && !selection[0].IsFolder)
{
var preview = AssetPreview.GetAssetPreview(AssetDatabase.LoadMainAssetAtPath(selection[0].RelativePath));
content = new GUIContent(preview);
}
//Draw Folder icon
else if (bDraw)
content = EditorGUIUtility.IconContent("Folder Icon");
GUILayout.Label(content,GUILayout.Width(Height), GUILayout.Height(Height));
}
private void deleteUnusedAssets()
{
int choice = EditorUtility.DisplayDialogComplex("Delete unused assets", "Do you want to delete the selected assets", "Yes", "Cancel", "Backup");
List<string> affectedAssets = new List<string>();
if (choice == 0)//Delete
{
foreach (var item in selection)
{
affectedAssets.Add(item.RelativePath);
}
deleteMultipleAssets(affectedAssets);
}
else if (choice == 2)//Backup
{
foreach (var item in selection)
{
affectedAssets.Add(item.RelativePath);
exportAssetsToPackage("Backup as unitypackage", affectedAssets);
}
}
}
private void deleteUnusedFromFolder(AH_TreeviewElement folder)
{
deleteUnusedFromFolder("Delete unused assets from folder", "Do you want to delete all unused assets from:" + Environment.NewLine + folder.RelativePath, folder);
}
private void deleteUnusedFromFolder(string header, string description, AH_TreeviewElement folder)
{
int choice = EditorUtility.DisplayDialogComplex(header, description, "Yes", "Cancel", "Backup (Slow)");
List<string> affectedAssets = new List<string>();
if (choice != 1)//Not Cancel
{
//Collect affected assets
affectedAssets = folder.GetUnusedPathsRecursively();
}
if (choice == 0)//Delete
{
deleteMultipleAssets(affectedAssets);
}
else if (choice == 2)//Backup
{
exportAssetsToPackage("Backup as unitypackage", affectedAssets);
}
}
private void exportAssetsToPackage(string header, List<string> affectedAssets)
{
string filename = Environment.UserName + "_Backup_" + "_" + AH_SerializationHelper.GetDateString();
string savePath = EditorUtility.SaveFilePanel(
header,
AH_SerializationHelper.GetBackupFolder(),
filename,
"unitypackage");
if (!string.IsNullOrEmpty(savePath))
{
EditorUtility.DisplayProgressBar("Backup", "Creating backup of " + affectedAssets.Count() + " assets", 0f);
AssetDatabase.ExportPackage(affectedAssets.ToArray<string>(), savePath, ExportPackageOptions.Default);
EditorUtility.ClearProgressBar();
EditorUtility.RevealInFinder(savePath);
deleteMultipleAssets(affectedAssets);
}
}
private void deleteMultipleAssets(List<string> affectedAssets)
{
double startTime = EditorApplication.timeSinceStartup;
for (int i = 0; i < affectedAssets.Count(); i++)
{
EditorUtility.DisplayProgressBar("Deleting unused assets", "Deleting " + i + "/" + affectedAssets.Count() + Environment.NewLine + affectedAssets[i], ((float)i) / ((float)affectedAssets.Count()));
}
#if UNITY_2020_1_OR_NEWER
List<string> failedPaths = new List<string>();
AssetDatabase.DeleteAssets(affectedAssets.ToArray(), failedPaths);
#else
foreach (var asset in affectedAssets)
{
AssetDatabase.DeleteAsset(asset);
}
#endif
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
if (OnAssetDeleted != null)
OnAssetDeleted();
}
}
}