static TargetTypeEnum GetTargetType(WindowData windowData1, Object obj) { if (obj == null) { return(TargetTypeEnum.File); } var targetTypeEnum = TargetTypeEnum.Directory; var path = AssetDatabase.GetAssetPath(obj); switch (windowData1.FindFrom) { case FindModeEnum.File when obj is DefaultAsset: targetTypeEnum = TargetTypeEnum.Directory; break; case FindModeEnum.File when path.LastIndexOf(".unity", StringComparison.Ordinal) != -1: targetTypeEnum = TargetTypeEnum.Scene; break; case FindModeEnum.File: targetTypeEnum = TargetTypeEnum.File; break; case FindModeEnum.Scene: targetTypeEnum = TargetTypeEnum.ObjectInScene; break; case FindModeEnum.Stage: targetTypeEnum = TargetTypeEnum.ObjectInStage; break; } return(targetTypeEnum); }
static void DrawRowFile(Result data, SearchResultGui gui, WindowData windowData) { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { var buf = GUI.color; var pingGo = data.MainFile == null ? data.RootGo : data.MainFile; if (GUILayout.Button(gui.Label, windowData.Style.RowMainAssetBtn)) { if (windowData.Click.IsDoubleClick(pingGo)) { // _selectionChangedByArrows = false; Selection.activeObject = pingGo; } else { EditorGUIUtility.PingObject(pingGo); } windowData.Click = new PrevClick(pingGo); } GUI.color = buf; EditorGUI.BeginChangeCheck(); if (data.File) { foreach (var prop in gui.Properties) { using (new EditorGUILayout.HorizontalScope()) { var locked = prop.Property.objectReferenceValue is MonoScript; var f = GUI.enabled; if (locked) { GUI.enabled = false; } EditorGUILayout.PropertyField(prop.Property, prop.Content, false); if (locked) { GUI.enabled = f; } } } } if (EditorGUI.EndChangeCheck()) { gui.SerializedObject.ApplyModifiedProperties(); // dependency.SerializedObject.Update(); } } }
void RenderRows(WindowData windowData) { // todo show spinner until scene is loaded, if (FileResultRows.GetEntitiesCount() > 0) { windowData.ExpandFiles = EditorGUILayout.Foldout(windowData.ExpandFiles, $"Usages in Project: {FileResultRows.GetEntitiesCount()}"); } if (SearchArgMain.IsEmpty()) { return; } if (windowData.ExpandFiles && windowData.FindFrom == FindModeEnum.File) { foreach (var i in FileResultRows.Out(out var get1, out var get2, out _, out _)) { DrawRowFile(get1[i], get2[i], windowData); } } var sceneMessage = $"Usages in Scenes: {ScenePaths.GetEntitiesCount()}"; if (ScenePaths.GetEntitiesCount() > 0) { windowData.ExpandScenes = EditorGUILayout.Foldout(windowData.ExpandScenes, sceneMessage); } if (!windowData.ExpandScenes) { return; } if (windowData.ExpandScenes && windowData.FindFrom == FindModeEnum.Scene) { foreach (var(grp, indices) in SceneResultRows.Out(out _, out var get2, out _, out _) .GroupBy1(ResultComp.Instance)) { using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { var count = 0; foreach (var i in indices) { if (count++ == 0) { if (GUILayout.Button(get2[i].Label, windowData.Style.RowMainAssetBtn)) { if (windowData.Click.IsDoubleClick(grp.RootGo)) { // _selectionChangedByArrows = false; Selection.activeObject = grp.RootGo; } else { EditorGUIUtility.PingObject(grp.RootGo); } windowData.Click = new PrevClick(grp.RootGo); } } DrawRowScene(get2[i]); } } } } using (new GUILayout.HorizontalScope()) { GUILayout.Space(windowData.Style.SceneIndent1); using (new EditorGUILayout.VerticalScope()) { foreach (var i1 in ScenePaths.Out(out var get1, out var get2, out _)) { windowData.SceneFoldout.text = get1[i1].PathNicified; var details = get2[i1]; details.SearchRequested = details.Scene.isLoaded; details.SearchRequested = EditorGUILayout.Foldout(details.SearchRequested, windowData.SceneFoldout, EditorStyles.foldout); if (details.SearchRequested && details.Scene.isLoaded && !details.SearchDone) { var mainArg = SearchArgMain.GetSingle(); mainArg.Scene = SceneManager.GetSceneByPath(details.Scene.path); SearchUtils.InScene(mainArg, details.Scene); details.SearchDone = true; } if (!details.SearchRequested) { if (!details.Scene.isLoaded) { continue; } if (!details.WasOpened) { // to clean up on selection change AufCtx.World.NewEntityWith(out SceneToClose comp); comp.Scene = details.Scene; comp.ForceClose = true; } foreach (var row in SceneResultRows.Out(out _, out _, out var get3, out var entities)) { if (!get3[row].ScenePath.Eq(details.Path)) { continue; } entities[row].Destroy(); } details.SearchDone = false; } else { if (!details.Scene.isLoaded) { details.Scene = EditorSceneManager.OpenScene(details.Path, OpenSceneMode.Additive); // to clean up on selection change AufCtx.World.NewEntityWith(out SceneToClose comp); comp.Scene = details.Scene; comp.SelectionId = Globals <PersistentUndoRedoState> .Value.Id; #if UNITY_2019_1_OR_NEWER EditorSceneManager.SetSceneCullingMask(details.Scene, 0); #endif details.SearchRequested = true; // todo Scope component #if later if (details.Scene.isLoaded) { EditorSceneManager.CloseScene(details.Scene, false); } #endif } else if (SceneResultRows.IsEmpty()) { EditorGUILayout.LabelField("No in-scene dependencies found."); } else { using (new GUILayout.HorizontalScope()) { GUILayout.Space(windowData.Style.SceneIndent2); using (new EditorGUILayout.VerticalScope()) foreach (var(grp, indices) in SceneResultRows .Out(out var g1, out var g2, out var g3, out _) .GroupBy1(ResultComp.Instance)) { var any = false; foreach (var i3 in indices) { if (!g3[i3].ScenePath.Eq(details.Path)) { continue; } any = true; break; } if (!any) { continue; } using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { var count = 0; foreach (var i2 in indices) { if (!g3[i2].ScenePath.Eq(details.Path)) { continue; } if (count++ == 0) { Result comp = g1[i2]; if (GUILayout.Button(g2[i2].Label, windowData.Style.RowMainAssetBtn)) { if (windowData.Click.IsDoubleClick(grp.RootGo)) { // _selectionChangedByArrows = false; Selection.activeObject = comp.RootGo; } else { EditorGUIUtility.PingObject(comp.RootGo); } windowData.Click = new PrevClick(comp.RootGo); } } DrawRowScene(g2[i2]); } } } } } } } } } }
static bool AskDeleteUnusedScenes(SearchArg arg, List <string> unusedScenes, WindowData windowData) { if (arg == null || unusedScenes == null) { return(false); } var hasUnusedScenes = unusedScenes.Count > 0; var previous = GUI.enabled; GUI.enabled = hasUnusedScenes; var guiContentRemoveScenes = windowData.Style.RemoveScene; if (GUILayout.Button(guiContentRemoveScenes, windowData.Style.RemoveUnusedBtn)) { var choice = EditorUtility.DisplayDialog( title: "Asset Cleaner", message: $"Do you really want to remove {unusedScenes.Count} scene(s)?", ok: "Remove", cancel: "Cancel"); if (choice) { EditorApplication.ExecuteMenuItem("File/Save Project"); var i = 0f; var total = (float)unusedScenes.Count; foreach (var scene in unusedScenes) { var path = Application.dataPath.Replace("Assets", scene); DeleteWithMeta(path); if (total >= _progressBarShowFromLevel) { var percent = i * 100 / total; if (Math.Abs(percent % 5f) < 0.01f) { if (EditorUtility.DisplayCancelableProgressBar( "Please wait...", "Deleting scenes...", percent)) { throw new Exception("Deleting aborted"); } } i++; } } if (total >= _progressBarShowFromLevel) { EditorUtility.ClearProgressBar(); } AssetDatabase.Refresh(); SearchUtils.Upd(arg); } GUI.enabled = previous; return(true); } GUI.enabled = previous; return(false); }
BacklinkStore.UnusedQty ShowObjectName(BacklinkStore store, WindowData windowData, TargetTypeEnum targetTypeEnum, SearchArg arg, string[] selectedGuids) { float TextWidth() { _buf2.text = _contentBuf.text; return(20f + GUI.skin.button.CalcSize(_buf2).x); } if (arg == null || arg.Main == null) { return(new BacklinkStore.UnusedQty()); } bool isMultiSelect = selectedGuids != null && selectedGuids.Length > 1; if (_contentBuf == null) { _contentBuf = new GUIContent { tooltip = $"Click to ping" }; } _contentBuf.image = isMultiSelect ? windowData.Style.MultiSelect.image : AssetPreview.GetMiniThumbnail(arg.Target); _contentBuf.text = string.Empty; _contentBuf.tooltip = string.Empty; if (!isMultiSelect) { switch (targetTypeEnum) { case TargetTypeEnum.Directory: if (!SearchArgMain.IsEmpty()) { _contentBuf.text = $"{arg.Main.name} (Folder)"; if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn, GUILayout.MinWidth(TextWidth()))) { EditorGUIUtility.PingObject(arg.Main); } if (AskDeleteUnusedFiles(arg, arg.UnusedAssetsFiltered, windowData)) { return(new BacklinkStore.UnusedQty()); } if (AskDeleteUnusedScenes(arg, arg.UnusedScenesFiltered, windowData)) { return(new BacklinkStore.UnusedQty()); } } break; case TargetTypeEnum.File: _contentBuf.text = $"{arg.Main.name} (File Asset)"; if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn, GUILayout.MinWidth(TextWidth()))) { EditorGUIUtility.PingObject(arg.Main); } bool hasUnusedFile = SearchUtils.IsUnused(arg.FilePath); var previous = GUI.enabled; GUI.enabled = hasUnusedFile; if (GUILayout.Button(windowData.Style.RemoveFile, windowData.Style.RemoveUnusedBtn)) { var choice = EditorUtility.DisplayDialog( title: "Asset Cleaner", message: $"Do you really want to remove file: \"{arg.Main.name}\"?", ok: "Remove", cancel: "Cancel"); if (choice) { EditorApplication.ExecuteMenuItem("File/Save Project"); DeleteWithMeta(arg.FilePath); AssetDatabase.Refresh(); SearchUtils.Upd(arg); } } GUI.enabled = previous; break; case TargetTypeEnum.Scene: _contentBuf.text = $"{arg.Main.name} (Scene)"; if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn, GUILayout.MinWidth(TextWidth()))) { EditorGUIUtility.PingObject(arg.Main); } bool hasUnusedScene = SearchUtils.IsUnused(arg.FilePath); previous = GUI.enabled; GUI.enabled = hasUnusedScene; if (GUILayout.Button(windowData.Style.RemoveScene, windowData.Style.RemoveUnusedBtn)) { var choice = EditorUtility.DisplayDialog( title: "Asset Cleaner", message: $"Do you really want to remove scene: {arg.Main.name}?", ok: "Remove", cancel: "Cancel"); if (choice) { EditorApplication.ExecuteMenuItem("File/Save Project"); DeleteWithMeta(arg.FilePath); AssetDatabase.Refresh(); SearchUtils.Upd(arg); } } GUI.enabled = previous; break; case TargetTypeEnum.ObjectInScene: _contentBuf.text = $"{arg.Main.name} (Object in Scene)"; if (GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn, GUILayout.MinWidth(TextWidth()))) { EditorGUIUtility.PingObject(arg.Main); } break; case TargetTypeEnum.ObjectInStage: _contentBuf.image = AssetPreview.GetMiniThumbnail(arg.Target); _contentBuf.text = $"{arg.Main.name} (Object in Staging)"; if (GUILayout.Button(_contentBuf, windowData.Style.RemoveUnusedBtn)) { EditorGUIUtility.PingObject(arg.Main); } break; default: if (GUILayout.Button($"{arg.Main.name} (Unknown Object Type)", windowData.Style.RemoveUnusedBtn)) { EditorGUIUtility.PingObject(arg.Main); } break; } } else { var unusedAssets = new List <string>(); var unusedScenes = new List <string>(); foreach (var guid in selectedGuids) { var path = AssetDatabase.GUIDToAssetPath(guid); if (store.UnusedFiles.TryGetValue(path, out _)) { unusedAssets.Add(path); } else if (store.UnusedScenes.TryGetValue(path, out _)) { unusedScenes.Add(path); } if (store.FoldersWithQty.TryGetValue(path, out _)) { SearchArg searchArg = new SearchArg() { FilePath = path, Target = AssetDatabase.LoadAssetAtPath <DefaultAsset>(path), Main = AssetDatabase.LoadAssetAtPath <DefaultAsset>(path) }; SearchUtils.Upd(searchArg); foreach (var unusedAssetPath in searchArg.UnusedAssetsFiltered) { if (store.UnusedFiles.TryGetValue(unusedAssetPath, out _)) { unusedAssets.Add(unusedAssetPath); } } foreach (var unusedScenePath in searchArg.UnusedScenesFiltered) { if (store.UnusedScenes.TryGetValue(unusedScenePath, out _)) { unusedScenes.Add(unusedScenePath); } } } } unusedAssets = unusedAssets.Distinct().ToList(); unusedScenes = unusedScenes.Distinct().ToList(); var assetSize = unusedAssets.Sum(CommonUtils.Size); var sceneSize = unusedScenes.Sum(CommonUtils.Size); _contentBuf.text = $"Assets: {unusedAssets.Count} ({CommonUtils.BytesToString(assetSize)}), Scenes: {unusedScenes.Count} ({CommonUtils.BytesToString(sceneSize)})"; ; GUILayout.Button(_contentBuf, windowData.Style.CurrentBtn, GUILayout.MinWidth(TextWidth())); if (AskDeleteUnusedFiles(arg, unusedAssets, windowData)) { return(new BacklinkStore.UnusedQty()); } if (AskDeleteUnusedScenes(arg, unusedScenes, windowData)) { return(new BacklinkStore.UnusedQty()); } return(new BacklinkStore.UnusedQty(unusedAssets.Count, unusedScenes.Count, assetSize + sceneSize)); } return(new BacklinkStore.UnusedQty()); }
void ShowTabMain(Config conf, WindowData windowData) { var store = Globals <BacklinkStore> .Value; EditorGUIUtility.labelWidth = windowData.Window.position.width * .7f; int Hash() => DirtyUtils.HashCode(conf.Locked); var active = SearchArgMain.Get1[0]; if (conf.Locked && (windowData.FindFrom == FindModeEnum.File && (active == null || active.Main == null || !AssetDatabase.Contains(active.Main)))) { conf.Locked = false; AufCtx.World.NewEntityWith(out RequestRepaintEvt _); } var style = windowData.Style; var hash = Hash(); if (hash != Hash()) { PersistenceUtils.Save(in conf); AufCtx.World.NewEntityWith(out RequestRepaintEvt _); } // if (Globals<WindowData>.Get() == null) return; EditorGUILayout.Space(); SearchArg arg = default; foreach (var i in SearchArgMain) { arg = SearchArgMain.Get1[i]; if (arg != null && arg.Main != null) { break; } } if (arg == default) { return; } var targetTypeEnum = GetTargetType(windowData, arg?.Main); BacklinkStore.UnusedQty unusedQty = new BacklinkStore.UnusedQty(0, 0, 0); using (new EditorGUILayout.HorizontalScope()) { var enabledBuf = GUI.enabled; var selectedGuids = Selection.assetGUIDs; var undoRedoState = Globals <UndoRedoState> .Value; GUI.enabled = selectedGuids != null && !conf.Locked && undoRedoState.UndoEnabled; if (GUILayout.Button(style.ArrowL, style.ArrowBtn)) { AufCtx.World.NewEntityWith(out UndoEvt _); } GUI.enabled = selectedGuids != null && !conf.Locked && undoRedoState.RedoEnabled; if (GUILayout.Button(style.ArrowR, style.ArrowBtn)) { AufCtx.World.NewEntityWith(out RedoEvt _); } GUI.enabled = enabledBuf; if (conf.Locked) { if (GUILayout.Button(style.Lock, style.LockBtn)) { AufCtx.World.NewEntityWith(out SelectionChanged selectionChanged); conf.Locked = false; if (Selection.activeObject != arg.Target) { selectionChanged.From = FindModeEnum.Scene; selectionChanged.Scene = SceneManager.GetActiveScene(); selectionChanged.Target = Selection.activeObject; } else if (Selection.assetGUIDs is string[] guids) { // todo show info box multiple selection is unsupported if (guids.Length > 0) { var path = AssetDatabase.GUIDToAssetPath(guids[0]); selectionChanged.Target = AssetDatabase.LoadAssetAtPath <Object>(path); switch (Selection.selectionChanged.Target) { case DefaultAsset _: selectionChanged.From = FindModeEnum.File; break; case GameObject go when go.scene.isLoaded: selectionChanged.From = FindModeEnum.Scene; selectionChanged.Scene = SceneManager.GetActiveScene(); break; default: selectionChanged.From = FindModeEnum.File; break; } } else if (Selection.activeObject is GameObject go && go.scene.isLoaded) { selectionChanged.From = FindModeEnum.Scene; selectionChanged.Target = Selection.activeObject; selectionChanged.Scene = SceneManager.GetActiveScene(); } } } } else { var enabled = GUI.enabled; GUI.enabled = selectedGuids != null && selectedGuids.Length == 1; if (GUILayout.Button(style.Unlock, style.UnlockBtn)) { conf.Locked = true; } GUI.enabled = enabled; } unusedQty = ShowObjectName(store, windowData, targetTypeEnum, arg, selectedGuids); } bool isMultiSelect = Selection.assetGUIDs != null && Selection.assetGUIDs.Length > 1; if (conf.ShowInfoBox) { if (isMultiSelect && (unusedQty.UnusedFilesQty + unusedQty.UnusedScenesQty > 0)) { var msgUnusedFiles = (unusedQty.UnusedFilesQty > 0) ? $"unused files ({unusedQty.UnusedFilesQty})," : ""; var msgUnusedScenes = (unusedQty.UnusedScenesQty > 0) ? $"unused scenes ({unusedQty.UnusedScenesQty})," : ""; var msgMultiSelect = $"This multi-selection contains: " + msgUnusedFiles + msgUnusedScenes + $"\nYou could delete them pressing corresponding button to the right."; EditorGUILayout.HelpBox(msgMultiSelect, MessageType.Info); } else if (TryGetHelpInfo(arg, out var msg, out var msgType)) { EditorGUILayout.HelpBox(msg, msgType); } } if (targetTypeEnum != TargetTypeEnum.Directory && !isMultiSelect) { var windowData2 = Globals <WindowData> .Value; EditorGUILayout.BeginVertical(); { windowData2.ScrollPos = EditorGUILayout.BeginScrollView(windowData2.ScrollPos); { RenderRows(windowData2); //TODO? EditorGUILayout.Space(); } EditorGUILayout.EndScrollView(); } EditorGUILayout.EndVertical(); EditorGUILayout.Space(); } }