From 36f798462d5ee78df294ead5fb5a8ea1e372fbed Mon Sep 17 00:00:00 2001
From: chai <chaifix@163.com>
Date: Tue, 10 Jul 2018 11:50:10 +0800
Subject: =?UTF-8?q?+=E5=AE=9A=E4=BD=8D=E8=A2=AB=E9=80=89=E4=B8=AD=E7=9A=84?=
 =?UTF-8?q?=E8=B5=84=E6=BA=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 AssetBrowser.cs | 650 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 499 insertions(+), 151 deletions(-)

diff --git a/AssetBrowser.cs b/AssetBrowser.cs
index 4be9386..398c2c2 100644
--- a/AssetBrowser.cs
+++ b/AssetBrowser.cs
@@ -1,42 +1,71 @@
-using UnityEditor;
+/////////////////////////////////////////////////////////////////////////////////
+//
+//  author: chaifeixiang
+//  date:   2018.5.20
+//  desc:   Unity中找文件依赖关系的编辑器工具,需要Unity5.4及以上版本
+//					
+//
+//					
+//					
+//
+/////////////////////////////////////////////////////////////////////////////////
+
+using UnityEditor;
 using UnityEngine;
 using System;
 using System.IO;
 using System.Collections;
 using System.Collections.Generic;
+using Object = UnityEngine.Object;
 
 class AssetData
 {
     // 枚举值为遍历的优先级,用于AssetData.Dependcies和AssetDataManager.Assets
-    public static readonly int AssetTypeCount = 9;
+    // 必须是紧凑的索引
     public enum AssetType
     {
-        Scene = 0, 
-        Prefab, 
+        Scene = 0,
+        Prefab,
         Mesh,
         Material,
-        Asset, 
-        Texture, 
-        Shader, 
-        Script, 
-        CSV, 
+        Asset,
+        Texture,
+        Shader,
+        Script,
+        CSV,
 
-        Unknown  = 255,
+        TypeCount,
+
+        Unknown = 255,
+    }
+    
+    public enum SubType
+    {
+        // Texture
+        png = 0, 
+        jpg, 
+        bmp, 
+        // Mesh 
+        fbx, 
+        FBX, 
+        //
+        Unknown = 255,
     }
 
     public AssetData(FileSystemInfo f)
     {
-        for (int i = 0; i < AssetTypeCount; ++i)
+        for (int i = 0; i < (int)AssetType.TypeCount; ++i)
             Dependencies[i] = new List<string>();
         AssetDataManager manager = AssetDataManager.Get();
         AssetPath = manager.FullPathToAssetPath(f.FullName);
         GUID = AssetDatabase.AssetPathToGUID(AssetPath);
         Name = f.Name;
         ObjType = AssetDatabase.GetMainAssetTypeAtPath(AssetPath);
-        FileType = ExtensionToAssetType(f.Extension);
         Extension = f.Extension;
-        string[] depsPath = AssetDatabase.GetDependencies(AssetPath, false); 
-        for(int i = 0; i < depsPath.Length; ++i)
+        FileType = ExtensionToAssetType(Extension);
+        SubFileType = ExtensionToSubType(Extension);
+        string[] depsPath = AssetDatabase.GetDependencies(AssetPath, false);
+        for (int i = 0; i < depsPath.Length; ++i)
         {
             string path = depsPath[i];
             string guid = AssetDatabase.AssetPathToGUID(path);
@@ -49,10 +78,10 @@ class AssetData
             Dependencies[(int)type].Add(guid);
             ++RefCount;
             List<string> data;
-            if (!AssetDataManager.AssetsReverse.TryGetValue(guid, out data))
+            if (!manager.AssetsReverse.TryGetValue(guid, out data))
             {
                 data = new List<string>();
-                AssetDataManager.AssetsReverse.Add(guid, data);
+                manager.AssetsReverse.Add(guid, data);
             }
             data.Add(GUID);
         }
@@ -64,17 +93,36 @@ class AssetData
     #region 资源属性
     public string GUID;
     public string Name;
-    public int    RefCount = 0;
-    public int    RevRefCount = 0; 
-    public long   DiskSize;
+    public int RefCount = 0;
+    //public int RevRefCount = 0;
+    public long DiskSize;
     public string DiskSizeStr;
     public string AssetPath;
-    public Type   ObjType;
+    public Type ObjType;
     public string Extension;
     public AssetType FileType;
-    public List<string>[] Dependencies = new List<string>[AssetTypeCount];
+    public SubType SubFileType;
+    public List<string>[] Dependencies = new List<string>[(int)AssetType.TypeCount];
     #endregion
 
+    private SubType ExtensionToSubType(string extension)
+    {
+        SubType subType = SubType.Unknown;
+        // texture
+        if (Extension == ".png")
+            subType = SubType.png;
+        else if (Extension == ".jpg")
+            subType = SubType.jpg;
+        else if (Extension == ".bmp")
+            subType = SubType.bmp;
+        // mesh
+        else if (Extension == ".fbx")
+            subType = SubType.fbx;
+        else if (Extension == ".FBX")
+            subType = SubType.FBX;
+        return subType;
+    }
+
     private AssetType ExtensionToAssetType(string extension)
     {
         if (extension == ".unity") return AssetType.Scene;
@@ -103,17 +151,17 @@ class AssetDataManager
 
     public AssetDataManager()
     {
-        for (int i = 0; i < AssetData.AssetTypeCount; ++i)
+        for (int i = 0; i < (int)AssetData.AssetType.TypeCount; ++i)
             Assets[i] = new Dictionary<string, AssetData>();
     }
 
     #region Asset字典
     // 所有资源
-    public static Dictionary<string, AssetData> AllAssets = new Dictionary<string, AssetData>();
+    public Dictionary<string, AssetData> AllAssets = new Dictionary<string, AssetData>();
     // 分类统计
-    public static Dictionary<string, AssetData>[] Assets = new Dictionary<string, AssetData>[AssetData.AssetTypeCount];
+    public Dictionary<string, AssetData>[] Assets = new Dictionary<string, AssetData>[(int)AssetData.AssetType.TypeCount];
     // 反向依赖
-    public static Dictionary<string, List<string>> AssetsReverse = new Dictionary<string, List<string>>();
+    public Dictionary<string, List<string>> AssetsReverse = new Dictionary<string, List<string>>();
     #endregion
 
     #region 过滤
@@ -130,13 +178,15 @@ class AssetDataManager
         ".csv"                  // CSV
     };
 
-    public string GetExtension(string file)
+    public string GetExtension(string path)
     {
-        if (file == null || file.Length == 0)
+        if (path == null || path.Length <= 0)
             return null;
-        int len = file.Length;
-        int idx = file.LastIndexOf('.');
-        return file.Substring(idx, len - idx);
+        int len = path.Length;
+        int idx = path.LastIndexOf('.');
+        if (idx == -1)
+            return null;
+        return path.Substring(path.LastIndexOf('.'), len - idx);
     }
 
     public bool IsValidFile(string file)
@@ -156,20 +206,18 @@ class AssetDataManager
 
     public bool IsValidFolder(string folderName)
     {
-        foreach(var dir in InvalidFolder)
+        foreach (var dir in InvalidFolder)
         {
-            if(dir == folderName)
+            if (dir == folderName)
                 return false;
         }
-        return true; 
+        return true;
     }
     #endregion
 
     public string FullPathToAssetPath(string fullpath)
     {
-        fullpath = fullpath.Replace('\\', '/');
-        string path = "Assets" + fullpath.Replace(Application.dataPath, "");
-        path = path.Replace('/', '\\');
+        string path = "Assets" + fullpath.Replace(Application.dataPath.Replace("/", "\\"), "");
         return path;
     }
 
@@ -183,13 +231,13 @@ class AssetDataManager
     {
         DirectoryInfo directoryInfo = new DirectoryInfo(fullpath);
         FileSystemInfo[] filesInfo = directoryInfo.GetFileSystemInfos();
-        foreach(FileSystemInfo f in filesInfo)
+        foreach (FileSystemInfo f in filesInfo)
         {
-            if(f is DirectoryInfo && IsValidFolder(f.Name))
+            if (f is DirectoryInfo && IsValidFolder(f.Name))
             {
                 LoadAssets(f.FullName);
             }
-            else if(f.Extension != ".meta" && IsValidFile(f.Name))
+            else if (f.Extension != ".meta" && IsValidFile(f.Name))
             {
                 AssetData asset = new AssetData(f);
                 AllAssets.Add(asset.GUID, asset);
@@ -198,6 +246,13 @@ class AssetDataManager
         }
     }
 
+    public string FormatPath(string assetpath)
+    {
+        string path = assetpath.Replace('/', '\\');
+        path = path.Replace("\\\\", "\\");
+        return path;
+    }
+
     public void ClearAssets()
     {
         AllAssets.Clear();
@@ -214,30 +269,33 @@ class Drawer
     {
         SelectorButtonStyle = new GUIStyle(GUIStyle.none);
         SelectorButtonStyle.normal.background = CreateTexture(1, 1, new Color32(62, 95, 150, 255));
+        MidAlignment = new GUIStyle(GUIStyle.none);
+        MidAlignment.alignment = TextAnchor.MiddleCenter;
     }
 
-    private Texture2D CreateTexture(int w, int h, Color col)
+    private Texture2D CreateTexture(int width, int height, Color color)
     {
-        Color[] pixels = new Color[w * h];
-        for(int i = 0; i < w * h; ++i)
-            pixels[i] = col;
-        Texture2D texture = new Texture2D(w, h);
-        texture.SetPixels(pixels);
-        return texture;
+        Color[] pixels = new Color[width * height];
+        for (int i = 0; i < width * height; ++i)
+            pixels[i] = color;
+        Texture2D result = new Texture2D(width, height);
+        result.SetPixels(pixels);
+        result.Apply();
+        return result;
     }
 
-    private static Drawer drawer = null; 
+    private static Drawer drawer = null;
 
     public static Drawer Get()
     {
         if (drawer == null)
             drawer = new Drawer();
-        return drawer; 
+        return drawer;
     }
-    
-    public void DrawButtonMid(Rect rect, string content)
+
+    public void DrawButtonMid(Rect rect, string content, out bool click)
     {
-        GUI.Button(rect, content, EditorStyles.miniButtonMid);
+        click = GUI.Button(rect, content, EditorStyles.miniButtonMid);
     }
 
     public void DrawButton(Rect rect, string content, out bool click)
@@ -270,7 +328,10 @@ class Drawer
 
     public void DrawFoldout(Rect rect, ref bool foldout)
     {
-        foldout = EditorGUI.Foldout(rect, foldout, "");
+        Texture2D foldIcon = foldout ? IconFoldout : IconFoldup;
+        bool clicked = GUI.Button(rect, foldIcon, MidAlignment);
+        if (clicked)
+            foldout = !foldout;
     }
 
     public void DrawAssetIcon(Rect rect, AssetData asset)
@@ -282,15 +343,38 @@ class Drawer
 
     public void DrawSelector(Rect rect, bool selected, out bool clicked)
     {
-        SelectorButtonStyle.normal.background = CreateTexture(1, 1, new Color32(62, 95, 150, 255));
-        clicked = GUI.Button(rect, "",selected ? SelectorButtonStyle : GUIStyle.none);
+        clicked = GUI.Button(rect, "", selected ? SelectorButtonStyle : GUIStyle.none);
+    }
+
+    public void DrawPing(Rect rect, ref bool clicked)
+    {
+        GUIContent content = EditorGUIUtility.IconContent("SubAssetCollapseButton");
+        clicked = GUI.Button(rect, content, MidAlignment);
+    }
+
+    public void SetTextColor(Color col)
+    {
+        drawColor = GUI.skin.label.normal.textColor;
+        GUI.skin.label.normal.textColor = col;
+    }
+
+    public void ResetTextColor()
+    {
+        GUI.skin.label.normal.textColor = drawColor;
     }
 
     #region 配置项
     public Color ColorHeavy = new Color(0.2f, 0.2f, 0.2f);
     public Color ColorLight = new Color(0.3f, 0.3f, 0.3f);
     public GUIStyle SelectorButtonStyle;
+    public Texture2D IconFoldout = EditorStyles.foldout.onNormal.background;
+    public Texture2D IconFoldup = EditorStyles.foldout.normal.background;
+    public GUIStyle MidAlignment;
     #endregion
+
+    #region 状态
+    private Color drawColor = new Color();
+    #endregion 
 }
 
 // 文件树
@@ -316,7 +400,10 @@ class AssetBrowser : EditorWindow
     private static AssetBrowser editor;
     private static Drawer drawer;
 
+    #region 目录
     private FileTree assetsTree = new FileTree();
+    private FileTree assetsTreeBuffer = new FileTree(); 
+    #endregion
 
     #region GUI 组件配置数值
     private Rect window = new Rect();
@@ -328,15 +415,15 @@ class AssetBrowser : EditorWindow
     private int filtersOffsetY = 27; // 过滤器Y偏移度
     private int headerOffsetY = 50; // 标题Y偏移度
     private int assetsTreeOffsetY = 70; // 列表偏移度
-    private int kTabWidth = 15;
+    private int kTabWidth = 13;
     #endregion
 
     #region 数据
-    private string directory = "";
     private FileTree.Node selectedNode = null;
     #endregion
 
     #region 过滤器
+    private string filterdirectory = "";
     private string filterFile = "";
     private bool filterScene = false;
     private bool filterPrefab = false;
@@ -349,7 +436,27 @@ class AssetBrowser : EditorWindow
     private bool filterCSV = false;
     #endregion
 
-    [MenuItem("Window/Asset Browser")]
+    #region 排序
+    private enum OrderBase
+    {
+        Name, 
+        Ref, 
+        RevRef, 
+        Type, 
+        DiskSize, 
+        Path
+    }
+    // 排序依据
+    private OrderBase orderBase = OrderBase.Path;
+    private int orderName = 1;
+    private int orderRef = 1;
+    private int orderRevRef = 1;
+    private int orderType = 1;
+    private int orderDiskSize = 1;
+    private int orderPath = 1;
+    #endregion
+
+    [MenuItem("DNTools/查找/资源引用关系", false, 6)]
     public static void Show()
     {
         editor = GetWindow<AssetBrowser>();
@@ -379,21 +486,21 @@ class AssetBrowser : EditorWindow
 
     private Dictionary<Colum, int> ColumWidth = new Dictionary<Colum, int>
     {
-        {Colum.Name, 500},
-        {Colum.Ref, 100},
-        {Colum.RevRef, 100},
-        {Colum.Type, 100},
-        {Colum.DiskSize, 100},
-        {Colum.Path, 500},
+        {Colum.Name, 450},
+        {Colum.Ref, 70},
+        {Colum.RevRef, 70},
+        {Colum.Type, 70},
+        {Colum.DiskSize, 70},
+        {Colum.Path, 870},
     };
 
-    private Dictionary<Colum, int> ColumOffsetX = new Dictionary<Colum, int>();
+    private Dictionary<Colum, int> ColumOffsetX = null;
 
     private void AdjustColumOffsetX()
     {
-        if (ColumOffsetX == null)
+        if (ColumOffsetX != null)
             return;
-        ColumOffsetX.Clear();
+        ColumOffsetX = new Dictionary<Colum, int>();
         ColumOffsetX.Add(Colum.Name, 0);
         ColumOffsetX.Add(Colum.Ref, ColumOffsetX[Colum.Name] + ColumWidth[Colum.Name]);
         ColumOffsetX.Add(Colum.RevRef, ColumOffsetX[Colum.Ref] + ColumWidth[Colum.Ref]);
@@ -406,13 +513,14 @@ class AssetBrowser : EditorWindow
     {
         window = editor.position;
     }
-
+     
     public void OnGUI()
     {
         // 调试
         if (editor == null)
             editor = GetWindow<AssetBrowser>();
-        drawer = Drawer.Get();
+        if (drawer == null)
+			drawer = Drawer.Get();
 
         AdjustColumOffsetX();
         AdjustWindow();
@@ -444,11 +552,44 @@ class AssetBrowser : EditorWindow
     private void OnDirectory()
     {
         float offsetY = directoryOffsetY + scrollPos.y;
-        drawer.DrawLabel(new Rect(0, offsetY, 95, kLineHeight), "资源目录 Assets/");
-        drawer.DrawTextfield(new Rect(95, offsetY, 250, kLineHeight), directory, ref directory);
-        bool load; 
+
+        Rect dragRect = new Rect(0, offsetY, 1000, 20);
+        string olddirectory = filterdirectory;
+        drawer.DrawLabel(new Rect(0, offsetY, 95, kLineHeight), "资源目录 Assets\\");
+        drawer.DrawTextfield(new Rect(95, offsetY, 250, kLineHeight), filterdirectory, ref filterdirectory);
+        if (filterdirectory == null)
+            filterdirectory = "";
+        // 拖拽
+        Event e = Event.current;
+        if (dragRect.Contains(e.mousePosition))
+        {
+            if (e.type == EventType.dragUpdated)
+                DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
+            else if (e.type == EventType.DragPerform)
+            {
+                Object[] objs = DragAndDrop.objectReferences;
+                e.Use();
+                if (DragAndDrop.objectReferences.Length > 0)
+                {
+                    Object obj = DragAndDrop.objectReferences[0];
+                    filterdirectory = AssetDatabase.GetAssetPath(obj);
+                    if (filterdirectory.Equals("Assets"))
+                    {
+                        filterdirectory = string.Empty;
+                    }
+                    else
+                    {
+                        filterdirectory = filterdirectory.Substring(7);
+                    }
+                }
+            }
+        }
+        filterdirectory = AssetDataManager.Get().FormatPath(filterdirectory);
+        if (filterdirectory != olddirectory)
+            ProcessTreeBuffer();
+        bool load;
         drawer.DrawButton(new Rect(350, offsetY, 50, kLineHeight), "载入", out load);
-        if(load)
+        if (load)
         {
             ProcessAssets();
             ProcessTree();
@@ -458,13 +599,23 @@ class AssetBrowser : EditorWindow
 
     private void OnFilters()
     {
+        string oldfilterfile = filterFile;
+        bool oldfilterScene = filterScene;
+        bool oldfilterPrefab = filterPrefab;
+        bool oldfilterMaterial = filterMaterial;
+        bool oldfilterAsset = filterAsset;
+        bool oldfilterMesh = filterMesh;
+        bool oldfilterTexture = filterTexture;
+        bool oldfilterShader = filterShader;
+        bool oldfilterScript = filterScript;
+        bool oldfilterCSV = filterCSV; 
         // 文件匹配
         drawer.DrawLabel(new Rect(0, filtersOffsetY + scrollPos.y, 100, kLineHeight), "匹配文件");
         drawer.DrawTextfield(new Rect(50, filtersOffsetY + scrollPos.y, 150, kLineHeight), filterFile, ref filterFile);
         // 类型过滤
         float offsetX = 250;
         float offsetY = filtersOffsetY + scrollPos.y;
-        int width = 70; 
+        int width = 70;
         drawer.DrawCheckBox(new Rect(offsetX, offsetY, width, kLineHeight), "场景", filterScene, ref filterScene);
         drawer.DrawCheckBox(new Rect(offsetX + width, offsetY, width, kLineHeight), "Prefab", filterPrefab, ref filterPrefab);
         drawer.DrawCheckBox(new Rect(offsetX + width * 2, offsetY, width, kLineHeight), "材质", filterMaterial, ref filterMaterial);
@@ -474,6 +625,19 @@ class AssetBrowser : EditorWindow
         drawer.DrawCheckBox(new Rect(offsetX + width * 6, offsetY, width, kLineHeight), "Shader", filterShader, ref filterShader);
         drawer.DrawCheckBox(new Rect(offsetX + width * 7, offsetY, width, kLineHeight), "脚本", filterScript, ref filterScript);
         drawer.DrawCheckBox(new Rect(offsetX + width * 8, offsetY, width, kLineHeight), "CSV", filterCSV, ref filterCSV);
+        // 刷新TreeBuffer
+        if( oldfilterfile != filterFile ||
+            oldfilterScene != filterScene||
+            oldfilterPrefab != filterPrefab||
+            oldfilterMaterial != filterMaterial||
+            oldfilterAsset != filterAsset||
+            oldfilterMesh != filterMesh||
+            oldfilterTexture != filterTexture||
+            oldfilterShader != filterShader||
+            oldfilterScript != filterScript||
+            oldfilterCSV != filterCSV
+        )
+            ProcessTreeBuffer();
     }
 
     private void OnAsset()
@@ -490,7 +654,7 @@ class AssetBrowser : EditorWindow
             new Rect(scrollPos.x, scrollPos.y + assetsTreeOffsetY, window.width, window.height - assetsTreeOffsetY),
             scrollPos,
             new Rect(0, 0, contentWidth, contentHeight - assetsTreeOffsetY),
-            false , false
+            false, false
         );
     }
 
@@ -502,44 +666,87 @@ class AssetBrowser : EditorWindow
     private void OnHeader()
     {
         float scrollY = scrollPos.y;
-        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Name], headerOffsetY + scrollY, ColumWidth[Colum.Name], kLineHeight), ColumHeader[Colum.Name]);
-        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Ref], headerOffsetY + scrollY, ColumWidth[Colum.Ref], kLineHeight), ColumHeader[Colum.Ref]);
-        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.RevRef], headerOffsetY + scrollY, ColumWidth[Colum.RevRef], kLineHeight), ColumHeader[Colum.RevRef]);
-        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Type], headerOffsetY + scrollY, ColumWidth[Colum.Type], kLineHeight), ColumHeader[Colum.Type]);
-        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.DiskSize], headerOffsetY + scrollY, ColumWidth[Colum.DiskSize], kLineHeight), ColumHeader[Colum.DiskSize]);
-        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Path], headerOffsetY + scrollY, ColumWidth[Colum.Path], kLineHeight), ColumHeader[Colum.Path]);
+        bool clickName = false;
+        bool clickRef = false;
+        bool clickRevRef = false;
+        bool clickType = false;
+        bool clickDiskSize = false;
+        bool clickPath = false;
+        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Name], headerOffsetY + scrollY, ColumWidth[Colum.Name], kLineHeight), ColumHeader[Colum.Name], out clickName);
+        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Ref], headerOffsetY + scrollY, ColumWidth[Colum.Ref], kLineHeight), ColumHeader[Colum.Ref], out clickRef);
+        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.RevRef], headerOffsetY + scrollY, ColumWidth[Colum.RevRef], kLineHeight), ColumHeader[Colum.RevRef], out clickRevRef);
+        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Type], headerOffsetY + scrollY, ColumWidth[Colum.Type], kLineHeight), ColumHeader[Colum.Type], out clickType);
+        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.DiskSize], headerOffsetY + scrollY, ColumWidth[Colum.DiskSize], kLineHeight), ColumHeader[Colum.DiskSize], out clickDiskSize);
+        drawer.DrawButtonMid(new Rect(ColumOffsetX[Colum.Path], headerOffsetY + scrollY, ColumWidth[Colum.Path], kLineHeight), ColumHeader[Colum.Path], out clickPath);
+        if(clickName)
+        {
+            orderBase = OrderBase.Name;
+            orderName = -orderName;
+            ReorderTreeBuffer();
+        }
+        else if (clickRef)
+        {
+            orderBase = OrderBase.Ref;
+            orderRef = -orderRef;
+            ReorderTreeBuffer();
+        }
+        else if (clickRevRef)
+        {
+            orderBase = OrderBase.RevRef;
+            orderRevRef = -orderRevRef;
+            ReorderTreeBuffer();
+        }
+        else if (clickType)
+        {
+            orderBase = OrderBase.Type;
+            orderType = -orderType;
+            ReorderTreeBuffer();
+        }
+        else if (clickDiskSize)
+        {
+            orderBase = OrderBase.DiskSize;
+            orderDiskSize = -orderDiskSize;
+            ReorderTreeBuffer();
+        }
+        else if (clickPath)
+        {
+            orderBase = OrderBase.Path;
+            orderPath = -orderPath;
+            ReorderTreeBuffer();
+        }
     }
 
     private void OnAssetsTree()
     {
         int count = 0;
-        foreach(FileTree.Node node in assetsTree.root)
+        foreach (FileTree.Node node in assetsTreeBuffer.root)
         {
             DrawNode(node, 0, ref count);
         }
     }
 
-    private bool Filter(FileTree.Node node, int hierachy)
+    private bool Filter(FileTree.Node node)
     {
-        if(hierachy == 0)
-        {
-            AssetData asset;
-            if (!AssetDataManager.AllAssets.TryGetValue(node.GUID, out asset))
-                return false;
-            // 文件类型过滤
-            if (asset.FileType == AssetData.AssetType.Scene && !filterScene) return false;
-            else if (asset.FileType == AssetData.AssetType.Prefab&& !filterPrefab) return false;
-            else if (asset.FileType == AssetData.AssetType.Material&& !filterMaterial) return false;
-            else if (asset.FileType == AssetData.AssetType.Asset&& !filterAsset) return false;
-            else if (asset.FileType == AssetData.AssetType.Mesh&& !filterMesh) return false;
-            else if (asset.FileType == AssetData.AssetType.CSV&& !filterCSV) return false;
-            else if (asset.FileType == AssetData.AssetType.Script&& !filterScript) return false;
-            else if (asset.FileType == AssetData.AssetType.Shader&& !filterShader) return false;
-            else if (asset.FileType == AssetData.AssetType.Texture&& !filterTexture) return false;
-            // 文件名
-            if (asset.Name.IndexOf(filterFile) == -1)
-                return false;
-        }
+        AssetData asset;
+        AssetDataManager assetDataManager = AssetDataManager.Get();
+        if (!assetDataManager.AllAssets.TryGetValue(node.GUID, out asset))
+            return false;
+        // 文件类型过滤
+        if (asset.FileType == AssetData.AssetType.Scene && !filterScene) return false;
+        else if (asset.FileType == AssetData.AssetType.Prefab && !filterPrefab) return false;
+        else if (asset.FileType == AssetData.AssetType.Material && !filterMaterial) return false;
+        else if (asset.FileType == AssetData.AssetType.Asset && !filterAsset) return false;
+        else if (asset.FileType == AssetData.AssetType.Mesh && !filterMesh) return false;
+        else if (asset.FileType == AssetData.AssetType.CSV && !filterCSV) return false;
+        else if (asset.FileType == AssetData.AssetType.Script && !filterScript) return false;
+        else if (asset.FileType == AssetData.AssetType.Shader && !filterShader) return false;
+        else if (asset.FileType == AssetData.AssetType.Texture && !filterTexture) return false;
+        // 文件路径
+        if (asset.AssetPath.IndexOf(filterdirectory) == -1)
+            return false;
+        // 文件名
+        if (asset.Name.IndexOf(filterFile) == -1)
+            return false;
 
         return true;
     }
@@ -547,8 +754,6 @@ class AssetBrowser : EditorWindow
     // 按照深度绘制
     private void DrawNode(FileTree.Node node, int hierachy, ref int count)
     {
-        if (!Filter(node, hierachy))
-            return;
         ++count;
         contentHeight = count * kLineHeight + assetsTreeOffsetY;
         DrawAssetInfo(node, hierachy, count - 1);
@@ -565,35 +770,52 @@ class AssetBrowser : EditorWindow
     {
         Drawer drawer = Drawer.Get();
         AssetData asset;
-        if (!AssetDataManager.AllAssets.TryGetValue(node.GUID, out asset))
+        AssetDataManager assetDataManager = AssetDataManager.Get();
+        if (!assetDataManager.AllAssets.TryGetValue(node.GUID, out asset))
             return;
         int offsetY = index * kLineHeight;
         // 绘制背景
         drawer.DrawBackground(new Rect(0, offsetY, contentWidth, kLineHeight), (index & 1) == 1 ? drawer.ColorHeavy : drawer.ColorLight);
+        // 绘制定位按钮
+        if(selectedNode == node)
+        {
+            bool ping = false;
+            drawer.DrawPing(new Rect(hierachy * kTabWidth, offsetY, 10, kLineHeight), ref ping);
+            if (ping)
+            {
+                Object obj = AssetDatabase.LoadAssetAtPath(asset.AssetPath, asset.ObjType);
+                if (obj)
+                {
+                    EditorGUIUtility.PingObject(obj);
+                }
+            }
+        }
         // 绘制折叠按钮
         if (node.Children.Count > 0)
-            drawer.DrawFoldout(new Rect(hierachy * kTabWidth, offsetY, 10, kLineHeight), ref node.Foldout);
+            drawer.DrawFoldout(new Rect(hierachy * kTabWidth + 7, offsetY, kLineHeight, kLineHeight), ref node.Foldout);
         // 绘制选择按钮
         bool clicked;
-        drawer.DrawSelector(new Rect(hierachy * kTabWidth + 12, offsetY, contentWidth, kLineHeight), selectedNode == node, out clicked);
+        drawer.DrawSelector(new Rect(hierachy * kTabWidth + 19 + 7, offsetY, contentWidth, kLineHeight), selectedNode == node, out clicked);
         if (clicked)
         {
-            if(selectedNode != node)
+            if (selectedNode != node)
                 selectedNode = node;
             else
             {
-                AssetReverse.Show(node.GUID);
-                selectedNode = null; 
+                AssetReverse.ShowWindow(node.GUID);
+                selectedNode = null;
             }
-        } 
+        }
+        if (selectedNode == node)
+            drawer.SetTextColor(Color.white);
         // 绘制图标
-        drawer.DrawAssetIcon(new Rect(hierachy * kTabWidth + 12, offsetY, ColumWidth[Colum.Name], kLineHeight), asset);
+        drawer.DrawAssetIcon(new Rect(hierachy * kTabWidth + 19 + 7, offsetY, ColumWidth[Colum.Name], kLineHeight), asset);
         // 绘制引用数
         drawer.DrawLabel(new Rect(ColumOffsetX[Colum.Ref], offsetY, 100, kLineHeight), asset.RefCount.ToString());
         // 绘制反向引用数
         List<string> revRef;
         int revRefCount = 0;
-        if (AssetDataManager.AssetsReverse.TryGetValue(node.GUID, out revRef))
+        if (assetDataManager.AssetsReverse.TryGetValue(node.GUID, out revRef))
             revRefCount = revRef.Count;
         drawer.DrawLabel(new Rect(ColumOffsetX[Colum.RevRef], offsetY, 100, kLineHeight), revRefCount.ToString());
         // 绘制资源类型
@@ -602,41 +824,104 @@ class AssetBrowser : EditorWindow
         drawer.DrawLabel(new Rect(ColumOffsetX[Colum.DiskSize], offsetY, 100, kLineHeight), asset.DiskSizeStr);
         // 绘制资源路径
         drawer.DrawLabel(new Rect(ColumOffsetX[Colum.Path], offsetY, 1000, kLineHeight), asset.AssetPath);
+        if (selectedNode == node)
+            drawer.ResetTextColor();
     }
 
     private void ProcessAssets()
     {
         AssetDataManager assetManager = AssetDataManager.Get();
         assetManager.ClearAssets();
-        assetManager.LoadAssets(assetManager.AssetPathToFullPath("Assets/" + directory));
+        assetManager.LoadAssets(assetManager.AssetPathToFullPath("Assets/"));
     }
 
     private void ProcessTree()
     {
         AssetDataManager assetManager = AssetDataManager.Get();
         assetsTree.root.Clear();
-        for(int i = 0; i < AssetData.AssetTypeCount; ++i)
+        for (int i = 0; i < (int)AssetData.AssetType.TypeCount; ++i)
         {
-            Dictionary<string, AssetData> assets = AssetDataManager.Assets[i];
-            foreach(var asset in assets)
+            Dictionary<string, AssetData> assets = assetManager.Assets[i];
+            foreach (var asset in assets)
             {
                 AssetData data = asset.Value;
                 FileTree.Node node = ProcessNode(data);
-                assetsTree.root.Add(node); 
+                assetsTree.root.Add(node);
             }
         }
+        ProcessTreeBuffer();
+    }
+
+    // 文件树缓冲
+    private void ProcessTreeBuffer()
+    {
+        assetsTreeBuffer.root.Clear();
+        foreach(FileTree.Node node in assetsTree.root)
+        {
+            if(!Filter(node))
+                continue; 
+            assetsTreeBuffer.root.Add(node);
+        }
+        orderBase = OrderBase.Path;
+        orderPath = 1;
+        ReorderTreeBuffer();
+    }
+
+    private int clamp(int n)
+    {
+        if (n > 0) return 1;
+        else if (n < 0) return -1;
+        else return 0;
+    }
+
+    // Tree Buffer重新排序
+    private void ReorderTreeBuffer()
+    {
+        assetsTreeBuffer.root.Sort((FileTree.Node a, FileTree.Node b) =>
+        {
+            AssetData aa, ab; 
+            AssetDataManager.Get().AllAssets.TryGetValue(a.GUID, out aa);
+            AssetDataManager.Get().AllAssets.TryGetValue(b.GUID, out ab);
+            if(aa == null || ab == null) 
+                return 0;
+            if (orderBase == OrderBase.Name) return clamp(orderName * aa.Name.CompareTo(ab.Name));
+            else if (orderBase == OrderBase.Ref) return clamp(orderRef * (aa.RefCount - ab.RefCount));
+            else if (orderBase == OrderBase.RevRef)
+            {
+                List<string> ra, rb;
+                int rac = 0, rbc = 0;
+                AssetDataManager.Get().AssetsReverse.TryGetValue(a.GUID, out ra);
+                AssetDataManager.Get().AssetsReverse.TryGetValue(b.GUID, out rb);
+                if (ra != null)
+                    rac = ra.Count;
+                if (rb != null)
+                    rbc = rb.Count;
+                return clamp(orderRevRef * (rac - rbc));
+            }
+            else if (orderBase == OrderBase.Type)
+            {
+                if(aa.FileType == ab.FileType)
+                {
+                    return clamp(orderType * ((int)aa.SubFileType - (int)ab.SubFileType));   
+                }
+                return clamp(orderType * ((int)aa.FileType - (int)ab.FileType));   
+            }
+            else if (orderBase == OrderBase.DiskSize) return clamp(orderDiskSize * (int)(aa.DiskSize - ab.DiskSize));
+            else if (orderBase == OrderBase.Path) return clamp(orderPath * aa.AssetPath.CompareTo(ab.AssetPath));
+            else return 1;
+        });
     }
 
     private FileTree.Node ProcessNode(AssetData data)
     {
         AssetDataManager assetManager = AssetDataManager.Get();
         FileTree.Node node = new FileTree.Node(data.GUID);
-        foreach(List<string> deps in data.Dependencies)
+        foreach (List<string> deps in data.Dependencies)
         {
-            foreach(string guid in deps)
+            foreach (string guid in deps)
             {
                 AssetData dep;
-                if(AssetDataManager.AllAssets.TryGetValue(guid, out dep))
+                if (assetManager.AllAssets.TryGetValue(guid, out dep))
                 {
                     FileTree.Node child = ProcessNode(dep);
                     node.Children.Add(child);
@@ -648,56 +933,119 @@ class AssetBrowser : EditorWindow
 
 }
 
-class AssetReverse : EditorWindow
+// 反向查找
+public class AssetReverse : EditorWindow
 {
-    private static AssetReverse editor;
     private static Drawer drawer;
-
+    private static AssetReverse editor;
+    private static AssetDataManager assetDataManager;
     private static string GUID;
-    private static AssetData asset;
-    private Vector2 scrollPos = new Vector2(0, 0);
-
-    private int kLineHeight = 20;
-    private int contentHeight = 0;
-
-    public static void Show(string guid)
+    private static AssetData resource = null;
+    public static void ShowWindow(string guid)
     {
         editor = GetWindow<AssetReverse>();
         editor.titleContent = new GUIContent("Asset Reverse");
+        drawer = Drawer.Get();
+        assetDataManager = AssetDataManager.Get();
+        AdjustkColumOffset();
         GUID = guid;
-        if(AssetDataManager.AllAssets.TryGetValue(GUID, out asset))
-        {
-        }
-        Drawer dawer = Drawer.Get();
+        if (!assetDataManager.AllAssets.TryGetValue(GUID, out resource))
+            resource = null;
     }
 
-    public void OnGUI()
+    private enum Colums
+    {
+        cName,     // "资源列表和引用关系"
+        cLocation, // "资源位置"
+    }
+
+    private static readonly Dictionary<Colums, string> kColumHeader = new Dictionary<Colums, string>{
+        {Colums.cName,     "资源名"},
+        {Colums.cLocation, "位置"},
+    };
+
+    private static readonly Dictionary<Colums, int> kColumWidth = new Dictionary<Colums, int>{
+        {Colums.cName,     300},
+        {Colums.cLocation, 500},
+    };
+
+    private static Dictionary<Colums, int> kColumOffset = null;
+
+    private static void AdjustkColumOffset()
     {
-        if (asset == null)
+        if (kColumOffset != null)
             return;
-        drawer = Drawer.Get();
-        drawer.DrawAssetIcon(new Rect(0, 0, 200, kLineHeight), asset);
-        scrollPos = GUI.BeginScrollView(new Rect(0, kLineHeight, editor.position.width, editor.position.height - kLineHeight), scrollPos, new Rect(0, 0, 1500, contentHeight));
-        // 标题
-        drawer.DrawButtonMid(new Rect(0, 0, 400, 20), "资源名");
-        drawer.DrawButtonMid(new Rect(400, 0, 400, 20), "资源路径");
-        // 
-        List<string> revRef;
-        if(AssetDataManager.AssetsReverse.TryGetValue(GUID, out revRef))
+        kColumOffset = new Dictionary<Colums, int>();
+        kColumOffset.Clear();
+        kColumOffset.Add(Colums.cName, 0);
+        kColumOffset.Add(Colums.cLocation, kColumWidth[Colums.cName] + kColumOffset[Colums.cName]);
+    }
+
+    private Rect windowRect;
+    private readonly int kLineHeight = 20;
+    private Vector2 scrollPos = new Vector2(0, 0);
+
+    private float ContentWidth = 1200;
+    private float ContentHeight = 20;
+    private int kListOffsetY = 40; // 2*kLineHeight
+
+    void OnGUI()
+    {
+        if (resource == null || GUID == null)
+            return;
+        AdjustWindowRect();
+        DrawHeader();
+        BeginScrollView();
+        DrawRevDepend();
+        EndScrollView();
+    }
+
+    private void DrawHeader()
+    {
+        GUIContent content = EditorGUIUtility.ObjectContent(null, resource.ObjType);
+        content.text = resource.AssetPath;
+        GUI.Label(new Rect(0, 0, 1000, kLineHeight), content);
+        GUI.Button(new Rect(kColumOffset[Colums.cName], kLineHeight, kColumWidth[Colums.cName], kLineHeight), kColumHeader[Colums.cName], EditorStyles.miniButtonMid);
+        GUI.Button(new Rect(kColumOffset[Colums.cLocation], kLineHeight, windowRect.width - kColumWidth[Colums.cName], kLineHeight), kColumHeader[Colums.cLocation], EditorStyles.miniButtonMid);
+    }
+
+    private void DrawRevDepend()
+    {
+        List<string> revDeps;
+        if (assetDataManager.AssetsReverse.TryGetValue(GUID, out revDeps))
         {
+            int yoffset = 0;
             int count = 0;
-            foreach(string guid in revRef)
+            ContentHeight = 0;
+            foreach (string guid in revDeps)
             {
-                AssetData data; 
-                if(AssetDataManager.AllAssets.TryGetValue(guid, out data))
+                AssetData resource;
+                if (assetDataManager.AllAssets.TryGetValue(guid, out resource))
                 {
-                    drawer.DrawAssetIcon(new Rect(0, kLineHeight + count * kLineHeight, 400, kLineHeight), data);
-                    drawer.DrawLabel(new Rect(400, kLineHeight + count * kLineHeight, 400, kLineHeight), data.AssetPath);
+                    drawer.DrawBackground(new Rect(0, yoffset, ContentWidth, kLineHeight), (count & 1) == 1 ? drawer.ColorHeavy : drawer.ColorLight);
+                    drawer.DrawAssetIcon(new Rect(0, yoffset, 1000, kLineHeight), resource);
+                    drawer.DrawLabel(new Rect(kColumOffset[Colums.cLocation], yoffset, 1000, kLineHeight), resource.AssetPath);
+                    yoffset += kLineHeight;
+                    ContentHeight += kLineHeight;
                     ++count;
-                    contentHeight = count * kLineHeight + kLineHeight;
                 }
             }
         }
+    }
+
+    private void BeginScrollView()
+    {
+        scrollPos = GUI.BeginScrollView(new Rect(0, kLineHeight * 2, windowRect.width, windowRect.height - kListOffsetY), scrollPos, new Rect(0, 0, windowRect.width, ContentHeight), false, true);
+    }
+
+    private void EndScrollView()
+    {
         GUI.EndScrollView();
     }
+
+    private void AdjustWindowRect()
+    {
+        windowRect = editor.position;
+        ContentWidth = windowRect.width;
+    }
 }
-- 
cgit v1.1-26-g67d0