Skip to content

Instantly share code, notes, and snippets.

@FlaShG

FlaShG/FavoritesWindow.cs

Last active Oct 18, 2020
Embed
What would you like to do?
A Unity EditorWindow to pin objects to for quick selection.
using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System.Collections.Generic;
/// <summary>
/// An editor window that lets you store assets and GameObjects in it for quickly finding them again.
/// </summary>
public class FavoritesWindow : EditorWindow
{
private struct BackgroundColor : System.IDisposable
{
private Color previousColor;
public BackgroundColor(Color color)
{
previousColor = GUI.backgroundColor;
GUI.backgroundColor = color;
}
public void Dispose()
{
GUI.backgroundColor = previousColor;
}
public static BackgroundColor Multiply(Color color)
{
return new BackgroundColor(color * GUI.backgroundColor);
}
}
[System.Serializable]
private struct ObjectInfo : ISerializationCallbackReceiver
{
public Object obj;
[SerializeField]
private string serializedId;
public GlobalObjectId id { get; private set; }
[SerializeField]
private string _name;
public string name => _name;
public ObjectInfo(Object obj)
{
this.obj = obj;
id = GlobalObjectId.GetGlobalObjectIdSlow(obj);
serializedId = id.ToString();
_name = obj.name;
}
public ObjectInfo(GlobalObjectId id, string name)
{
obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(id);
this.id = id;
serializedId = id.ToString();
_name = obj ? obj.name : name;
}
public override bool Equals(object obj)
{
if (GetType() != obj.GetType())
{
return false;
}
return this.obj == ((ObjectInfo)obj).obj;
}
public override int GetHashCode()
{
return obj.GetHashCode();
}
public void FindReferenceIfNull()
{
if (!obj)
{
obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(id);
}
}
public void OnBeforeSerialize() { }
public void OnAfterDeserialize()
{
GlobalObjectId.TryParse(serializedId, out var id);
this.id = id;
}
}
private ReorderableList list;
[SerializeField]
private List<ObjectInfo> items = default;
private static GUIStyle buttonStyle;
private static GUIStyle removeStyle;
private Vector2 scrollPosition;
[MenuItem("Window/Favorites")]
private static void Open()
{
GetWindow<FavoritesWindow>("★ Favorites");
}
private void OnEnable()
{
RefreshList();
}
private void OnHierarchyChange()
{
RefreshList();
}
private void GenerateList()
{
if (items == null)
{
items = new List<ObjectInfo>();
}
if (list != null) return;
list = new ReorderableList(items, typeof(Object), true, false, false, false);
list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
if (index >= items.Count)
{
GUI.Label(rect, "Error");
return;
}
var typeRect = new Rect(rect.x, rect.y, 150, rect.height);
var buttonRect = new Rect(typeRect.xMax, rect.y, rect.width - 30 - 150, rect.height);
var removeRect = new Rect(buttonRect.xMax + 5, rect.y, 25, rect.height);
if (items[index].obj != null)
{
GUI.Label(typeRect, items[index].obj.GetType().Name);
DisplayItemButton(items[index], buttonRect);
}
else
{
GUI.Label(typeRect, "Destroyed");
GUI.Label(buttonRect, items[index].name);
}
using (BackgroundColor.Multiply(new Color(1, 0.5f, 0.5f)))
{
if (GUI.Button(removeRect, "X", removeStyle))
{
items.RemoveAt(index);
}
}
};
}
private void DisplayItemButton(ObjectInfo info, Rect buttonRect)
{
if (info.obj.GetType() == typeof(SceneAsset))
{
var openButtonRect = new Rect(buttonRect);
openButtonRect.xMin = openButtonRect.xMax - 48;
if (GUI.Button(openButtonRect, "Open"))
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(AssetDatabase.GetAssetPath(info.obj));
}
buttonRect.xMax -= 50;
}
if (GUI.Button(buttonRect, info.name, buttonStyle))
{
Selection.activeObject = info.obj;
EditorGUIUtility.PingObject(info.obj);
}
}
private void OnGUI()
{
GenerateList();
GenerateStyles();
const int padding = 10;
var addRect = new Rect(padding, padding, position.width - padding * 2, EditorGUIUtility.singleLineHeight);
var newObject = EditorGUI.ObjectField(addRect, new GUIContent("Add object"), null, typeof(Object), true);
if (newObject)
{
var objectInfo = new ObjectInfo(newObject);
items.Remove(objectInfo);
items.Insert(0, objectInfo);
}
var scrollRect = new Rect(5, 35, position.width - 5, position.height - 35);
var viewRect = new Rect(0, 0, position.width - 20, items.Count * list.elementHeight + 28);
scrollPosition = GUI.BeginScrollView(scrollRect, scrollPosition, viewRect, false, true, GUIStyle.none, GUI.skin.verticalScrollbar);
list.DoList(viewRect);
GUI.EndScrollView();
}
private void GenerateStyles()
{
if (buttonStyle != null) return;
buttonStyle = new GUIStyle(GUI.skin.button);
buttonStyle.alignment = TextAnchor.MiddleLeft;
removeStyle = new GUIStyle(GUI.skin.button);
removeStyle.border = new RectOffset(4, 4, 4, 4);
}
private void RefreshList()
{
for (var i = 0; i < items.Count; i++)
{
if (items[i].obj == null)
{
items[i] = new ObjectInfo(items[i].id, items[i].name);
}
else
{
items[i] = new ObjectInfo(items[i].obj);
}
}
Repaint();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.