Skip to content

Instantly share code, notes, and snippets.

@MPozek
Last active July 16, 2020 20:44
Show Gist options
  • Select an option

  • Save MPozek/259e654d50c94dea3ebaaf4492a1efcc to your computer and use it in GitHub Desktop.

Select an option

Save MPozek/259e654d50c94dea3ebaaf4492a1efcc to your computer and use it in GitHub Desktop.
Quick access window is a unity editor window with support for storing links to assets you often use for... well quick access
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
public class QuickAccessWindow : EditorWindow
{
[System.Serializable]
public class Category
{
public string Name;
public string Filter;
public bool IsCustom = false;
public List<string> CustomGuidList = new List<string>();
}
[System.Serializable]
public class State
{
public int SelectedCategory;
public List<Category> Filters = new List<Category>()
{
new Category()
{
Name = "Scenes",
Filter = "t:scene"
}
};
}
[MenuItem("Assets/Quick access")]
public static void AddToCategory()
{
PickCustomCategoryPopup.CreateAndShow();
}
[MenuItem("Assets/Quick access", true)]
public static bool ValidateAddToCategory()
{
return Selection.activeObject;
}
[MenuItem("Utility/Quick access")]
public static void Open()
{
var window = (QuickAccessWindow)EditorWindow.GetWindow(typeof(QuickAccessWindow));
window.titleContent = new GUIContent("Quick Access");
window.Show();
}
[MenuItem("Utility/Quick access clear prefs")]
public static void ClearPrefs()
{
EditorPrefs.DeleteKey(EDITOR_PREFS_KEY);
}
private const string EDITOR_PREFS_KEY = "QuickAccessWindow_State";
private State _windowState;
private List<List<string>> _refreshedAssets;
private Vector2 _scrollPosition;
private bool _isNewCategoryCustom;
private bool _newFilterFoldout;
private string _newCategoryName;
private string _newCategoryFilter;
private void Load()
{
var serializedState = EditorPrefs.GetString(EDITOR_PREFS_KEY, null);
if (string.IsNullOrEmpty(serializedState))
{
_windowState = new State();
}
else
{
_windowState = JsonUtility.FromJson<State>(serializedState);
}
}
private void Save()
{
var serializedState = JsonUtility.ToJson(_windowState);
EditorPrefs.SetString(EDITOR_PREFS_KEY, serializedState);
}
private void AddToCustomCategory(Object[] objects, int categoryIndex)
{
var guidList = _windowState.Filters[categoryIndex].CustomGuidList;
for (int i = 0; i < objects.Length; i++)
{
var obj = objects[i];
var assetPath = AssetDatabase.GetAssetPath(obj);
if (string.IsNullOrEmpty(assetPath) == false)
{
var guid = AssetDatabase.AssetPathToGUID(assetPath);
if (guidList.Contains(guid) == false)
guidList.Add(guid);
}
}
RefreshFilter(categoryIndex);
Repaint();
}
private void OnEnable()
{
_refreshedAssets = new List<List<string>>();
Load();
Refresh();
}
private void OnDisable()
{
Save();
}
private void OnGUI()
{
_windowState.SelectedCategory = Mathf.Clamp(_windowState.SelectedCategory, 0, _windowState.Filters.Count - 1);
HandleDragAndDrop();
DrawNewCategoryFoldout();
if (_windowState.Filters.Count > 0)
{
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
for (int i = 0; i < _windowState.Filters.Count; i++)
{
if (i % 3 == 0)
{
EditorGUILayout.EndHorizontal();
EditorGUILayout.BeginHorizontal();
}
GUI.enabled = i != _windowState.SelectedCategory;
if (GUILayout.Button(_windowState.Filters[i].Name))
{
_windowState.SelectedCategory = i;
RefreshFilter(i);
}
GUI.enabled = true;
}
EditorGUILayout.EndHorizontal();
if (GUILayout.Button("Remove selected category"))
{
_windowState.Filters.RemoveAt(_windowState.SelectedCategory);
Refresh();
return;
}
if (GUILayout.Button("Refresh"))
{
RefreshFilter(_windowState.SelectedCategory);
}
EditorGUILayout.Space();
DrawSelectedCategoryList();
}
}
private void HandleDragAndDrop()
{
var category = _windowState.Filters[_windowState.SelectedCategory];
DragAndDrop.AcceptDrag();
if (category.IsCustom)
{
var ev = Event.current;
if (ev.type == EventType.DragUpdated)
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
}
if (ev.type == EventType.DragPerform)
{
ev.Use();
AddToCustomCategory(DragAndDrop.objectReferences, _windowState.SelectedCategory);
}
}
}
private void DrawNewCategoryFoldout()
{
_newFilterFoldout = EditorGUILayout.BeginFoldoutHeaderGroup(_newFilterFoldout, "New Category");
if (_newFilterFoldout)
{
_newCategoryName = EditorGUILayout.TextField("Name", _newCategoryName);
_isNewCategoryCustom = EditorGUILayout.Toggle("Custom category", _isNewCategoryCustom);
if (!_isNewCategoryCustom)
_newCategoryFilter = EditorGUILayout.TextField("Filter", _newCategoryFilter);
if (GUILayout.Button("+", GUILayout.Width(40f)))
{
if ((_isNewCategoryCustom || !string.IsNullOrEmpty(_newCategoryFilter)) && !string.IsNullOrEmpty(_newCategoryName))
{
_windowState.Filters.Add(new Category
{
Name = _newCategoryName,
IsCustom = _isNewCategoryCustom,
Filter = _newCategoryFilter
});
Refresh();
}
}
}
EditorGUILayout.EndFoldoutHeaderGroup();
}
private void DrawSelectedCategoryList()
{
var cat = _windowState.Filters[_windowState.SelectedCategory];
var l = _refreshedAssets[_windowState.SelectedCategory];
var maxWidthLabel = position.width * 0.65f;
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition, EditorStyles.helpBox);
EditorGUILayout.BeginVertical();
for (int i = 0; i < l.Count; i++)
{
EditorGUILayout.BeginHorizontal();
var assetName = System.IO.Path.GetFileNameWithoutExtension(l[i]);
var loadedAsset = AssetDatabase.LoadAssetAtPath<Object>(l[i]);
bool selectPressed = GUILayout.Button(
new GUIContent(assetName, AssetPreview.GetMiniThumbnail(loadedAsset)),
EditorStyles.label,
GUILayout.Height(20f),
GUILayout.MaxWidth(maxWidthLabel)
);
if (selectPressed)
{
SelectAsset(l[i]);
}
if (GUILayout.Button("Open", GUILayout.MaxWidth(position.width - maxWidthLabel)))
{
OpenAsset(l[i]);
}
if (cat.IsCustom && GUILayout.Button("X"))
{
cat.CustomGuidList.RemoveAt(i);
l.RemoveAt(i);
i--;
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
EditorGUILayout.EndScrollView();
}
private void OpenAsset(string path)
{
var loadedAsset = AssetDatabase.LoadAssetAtPath<Object>(path);
AssetDatabase.OpenAsset(loadedAsset);
}
private void SelectAsset(string path)
{
var asset = AssetDatabase.LoadAssetAtPath<Object>(path);
Selection.activeObject = asset;
ProjectWindowUtil.ShowCreatedAsset(asset);
}
private void Refresh()
{
if (_refreshedAssets.Count > _windowState.Filters.Count)
{
_refreshedAssets.RemoveRange(_windowState.Filters.Count, _refreshedAssets.Count - _windowState.Filters.Count);
}
else if (_refreshedAssets.Count < _windowState.Filters.Count)
{
for (int i = _refreshedAssets.Count; i < _windowState.Filters.Count; i++)
{
_refreshedAssets.Add(new List<string>());
}
}
for (int i = 0; i < _refreshedAssets.Count; i++)
{
_refreshedAssets[i].Clear();
}
for (int i = 0; i < _windowState.Filters.Count; i++)
{
RefreshFilter(i);
}
}
private void RefreshFilter(int i)
{
var category = _windowState.Filters[i];
var pathList = _refreshedAssets[i];
pathList.Clear();
IList<string> guids;
if (category.IsCustom)
{
guids = category.CustomGuidList;
}
else
{
guids = AssetDatabase.FindAssets(category.Filter);
}
foreach (var guid in guids)
{
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
pathList.Add(assetPath);
}
}
public class PickCustomCategoryPopup : EditorWindow
{
public static void CreateAndShow()
{
PickCustomCategoryPopup window = ScriptableObject.CreateInstance<PickCustomCategoryPopup>();
window._qaWindow = (QuickAccessWindow) EditorWindow.GetWindow(typeof(QuickAccessWindow));
int toggleCount = window._qaWindow._windowState.Filters.Select(c => c.IsCustom).Count();
window.position = new Rect(Screen.width / 2, Screen.height / 2, 250, toggleCount * EditorGUIUtility.singleLineHeight);
window.titleContent = new GUIContent("Choose custom category");
window.ShowModalUtility();
}
private QuickAccessWindow _qaWindow;
private int _selectedFilterIndex;
private void OnGUI()
{
EditorGUILayout.LabelField("Choose a custom category");
for (int i = 0; i < _qaWindow._windowState.Filters.Count; i++)
{
var f = _qaWindow._windowState.Filters[i];
if (f.IsCustom)
{
bool didSelect = EditorGUILayout.Toggle(f.Name, i == _selectedFilterIndex);
if (didSelect)
{
_selectedFilterIndex = i;
}
}
}
GUILayout.Space(70);
GUI.enabled = _qaWindow._windowState.Filters[_selectedFilterIndex].IsCustom;
if (GUILayout.Button("Add"))
{
AddSelection();
this.Close();
}
GUI.enabled = true;
if (GUILayout.Button("Cancel"))
{
this.Close();
}
}
private void AddSelection()
{
_qaWindow.AddToCustomCategory(Selection.objects, _selectedFilterIndex);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment