Last active
August 20, 2022 17:23
-
-
Save gengen1988/be7274d1f38bfbe188848b89186b1753 to your computer and use it in GitHub Desktop.
An Unity editor script to help navigating in hierarchy or project browser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEditor; | |
using UnityEngine; | |
[InitializeOnLoad] | |
public class SelectionHistory | |
{ | |
private const int MAX_HISTORY_COUNT = 10; | |
public static SelectionHistory Instance { get; private set; } | |
private bool skipRecord; | |
private SelectionSnapshot currentState; | |
private HistoryStack<SelectionSnapshot> back, forward; | |
static SelectionHistory() | |
{ | |
Instance = new SelectionHistory(); | |
Instance.Start(); | |
} | |
private void Start() | |
{ | |
currentState = TakeSnapshot(); | |
back = new HistoryStack<SelectionSnapshot>(MAX_HISTORY_COUNT); | |
forward = new HistoryStack<SelectionSnapshot>(MAX_HISTORY_COUNT); | |
Selection.selectionChanged += OnSelectionChanged; | |
} | |
private void OnSelectionChanged() | |
{ | |
// skip back or forward changes | |
if (skipRecord) | |
{ | |
skipRecord = false; | |
} | |
else | |
{ | |
RecordSelection(); | |
} | |
currentState = TakeSnapshot(); | |
} | |
[MenuItem("Selection / Back _[")] | |
private static void MenuItemBack() | |
{ | |
Instance.Back(); | |
} | |
[MenuItem("Selection / Forward _]")] | |
private static void MenuItemForward() | |
{ | |
Instance.Forward(); | |
} | |
private void RecordSelection() | |
{ | |
// do not record empty entry | |
if (IsDeselected()) | |
{ | |
return; | |
} | |
// do not record same entry | |
SelectionSnapshot latestHistory = back.Peek(); | |
if (latestHistory != null | |
&& latestHistory.ActiveObject == currentState.ActiveObject | |
&& latestHistory.Objects.SequenceEqual(currentState.Objects)) | |
{ | |
return; | |
} | |
back.Push(currentState); | |
forward.Clear(); | |
} | |
private void Back() | |
{ | |
if (back.Count == 0) | |
{ | |
return; | |
} | |
// prevent forward to null | |
if (!IsDeselected()) | |
{ | |
forward.Push(currentState); | |
} | |
SelectionSnapshot snapshot = back.Pop(); | |
RestoreSnapshot(snapshot); | |
} | |
private void Forward() | |
{ | |
if (forward.Count == 0) | |
{ | |
return; | |
} | |
back.Push(currentState); | |
SelectionSnapshot snapshot = forward.Pop(); | |
RestoreSnapshot(snapshot); | |
} | |
private SelectionSnapshot TakeSnapshot() | |
{ | |
return new SelectionSnapshot | |
{ | |
Window = EditorWindow.focusedWindow, | |
ActiveObject = Selection.activeObject, | |
Objects = Selection.objects | |
}; | |
} | |
private void RestoreSnapshot(SelectionSnapshot snapshot) | |
{ | |
skipRecord = true; | |
Selection.activeObject = snapshot.ActiveObject; | |
Selection.objects = snapshot.Objects; | |
snapshot.Window.Focus(); // TODO handle locked ProjectBrowser | |
EditorGUIUtility.PingObject(snapshot.ActiveObject); | |
} | |
private bool IsDeselected() | |
{ | |
return currentState == null || currentState.ActiveObject == null; | |
} | |
} | |
public class HistoryStack<T> | |
{ | |
private readonly int size; | |
private readonly LinkedList<T> collection; | |
public HistoryStack(int size) | |
{ | |
this.size = size; | |
collection = new LinkedList<T>(); | |
} | |
public void Push(T snapshot) | |
{ | |
collection.AddLast(snapshot); | |
// remove too old records | |
while (collection.Count > size) | |
{ | |
collection.RemoveFirst(); | |
} | |
} | |
public T Pop() | |
{ | |
T snapshot = collection.Last.Value; | |
collection.RemoveLast(); | |
return snapshot; | |
} | |
public T Peek() | |
{ | |
return collection.Count == 0 ? default : collection.Last.Value; | |
} | |
public void Clear() | |
{ | |
collection.Clear(); | |
} | |
public int Count => collection.Count; | |
} | |
public class SelectionSnapshot | |
{ | |
public EditorWindow Window; | |
public Object ActiveObject; | |
public Object[] Objects; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment