Last active
May 20, 2022 13:57
-
-
Save melsov/eda9a716c8cf81d4a2c459f8b0b62c81 to your computer and use it in GitHub Desktop.
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 UnityEngine; | |
using UnityEditor; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Linq; | |
using System; | |
// TODO / WARNING: This script has some jenky behavior that needs ironing out. | |
// You probably want to use somebody else's back-button-in-unity implementation. | |
// TRY HERE: https://forum.unity.com/threads/feature-request-back-button-in-the-editor.653332/#post-4457944 | |
namespace Mel.MLSelectionHistory | |
{ | |
public class MLHistory | |
{ | |
private MLHistory() | |
{ | |
Selection.selectionChanged += this.handleSelectionChange; | |
} | |
private static MLHistory _Instance; | |
public static MLHistory Instance | |
{ | |
get | |
{ | |
if (MLHistory._Instance == null) | |
{ | |
MLHistory._Instance = new MLHistory(); | |
MLHistory._Instance.clearAndSave(); | |
Debug.LogWarning("a new MLHistory is born"); | |
} | |
return MLHistory._Instance; | |
} | |
} | |
public Action onStateChanged; | |
void notifyStateChange() | |
{ | |
if (onStateChanged != null) | |
{ | |
onStateChanged.Invoke(); | |
} | |
} | |
private int[] selectionIDs; | |
List<int[]> history = new List<int[]>(); | |
private static int maxHistory = 50; | |
int cursor | |
{ | |
get { return EditorPrefs.GetInt(MEL_SelectionHistoryCursor); } | |
set { EditorPrefs.SetInt(MEL_SelectionHistoryCursor, value); } | |
} | |
int numEntries | |
{ | |
get { return EditorPrefs.GetInt(MEL_SelectionHistoryCount); } | |
set { EditorPrefs.SetInt(MEL_SelectionHistoryCount, value); } | |
} | |
void pruneAfterCursor() | |
{ | |
if (this.cursor >= this.history.Count - 1) | |
{ | |
return; | |
} | |
this.history.RemoveRange(this.cursor + 1, this.history.Count - (this.cursor + 1)); | |
} | |
void pushSelection() | |
{ | |
this.history.Add(Selection.instanceIDs); | |
this.numEntries = this.history.Count; | |
this.cursor = this.history.Count - 1; | |
} | |
bool isCurrentAlreadyRecorded() | |
{ | |
if (this.history.Count == 0) { return false; } | |
var last = this.history[this.cursor]; | |
if (last.Length != Selection.instanceIDs.Length) | |
{ | |
return false; | |
} | |
for (int i = 0; i < last.Length; ++i) | |
{ | |
if (last[i] != Selection.instanceIDs[i]) | |
{ | |
return false; | |
} | |
} | |
return true; | |
} | |
void shiftIfLimit() | |
{ | |
if (this.history.Count < MLHistory.maxHistory + 1) { return; } | |
this.history.RemoveAt(0); | |
} | |
public void handleSelectionChange() | |
{ | |
this.pruneAndPushCurrent(); | |
this.SaveHistory(); | |
this.notifyStateChange(); | |
} | |
void pruneAndPushCurrent() | |
{ | |
this.LoadHistory(); | |
if (this.isCurrentAlreadyRecorded()) | |
{ | |
return; | |
} | |
this.pruneAfterCursor(); | |
this.pushSelection(); | |
this.shiftIfLimit(); | |
this.SaveHistory(); | |
} | |
public void Dbug(string msg) | |
{ | |
// var output = EditorPrefs.GetString(MEL_SelectionHistory); | |
// output = " Cursor: " + this.cursor + output; | |
// Debug.Log(msg + output); | |
} | |
void selectCurrent() | |
{ | |
if (this.history.Count == 0) | |
{ | |
return; | |
} | |
if (this.cursor >= this.history.Count) | |
{ | |
return; | |
} | |
Selection.instanceIDs = this.history[this.cursor]; | |
} | |
public bool isForwardAvailable() | |
{ | |
return this.cursor < this.history.Count - 1; | |
} | |
public bool isBackAvailable() | |
{ | |
return this.cursor > 0; | |
} | |
public void clearAndSave() | |
{ | |
this.history.Clear(); | |
this.cursor = 0; | |
this.SaveHistory(); | |
this.notifyStateChange(); | |
} | |
public void moveBack() | |
{ | |
this.LoadHistory(); | |
if (!this.isBackAvailable()) | |
{ | |
return; | |
} | |
this.cursor--; | |
this.selectCurrent(); | |
this.notifyStateChange(); | |
} | |
public void moveForward() | |
{ | |
this.LoadHistory(); | |
if (!this.isForwardAvailable()) | |
{ | |
return; | |
} | |
this.cursor++; | |
this.selectCurrent(); | |
this.notifyStateChange(); | |
} | |
static string MEL_SelectionHistory = "__MEL_SelectionHistory__"; | |
static string MEL_SelectionHistoryCursor = "__MEL_SelectionHistoryCursor__"; | |
static string MEL_SelectionHistoryCount = "__MEL_SelectionHistoryCount__"; | |
StringBuilder sb = new StringBuilder(); | |
void SaveHistory() | |
{ | |
sb.Clear(); | |
foreach (var ids in this.history) | |
{ | |
for (int i = 0; i < ids.Length; ++i) | |
{ | |
sb.Append(ids[i].ToString()); | |
if (i < ids.Length - 1) | |
{ | |
sb.Append(";"); | |
} | |
} | |
sb.Append("|"); | |
} | |
var outString = sb.ToString().TrimEnd(char.Parse("|")); | |
EditorPrefs.SetString(MEL_SelectionHistory, outString); | |
this.numEntries = this.history.Count; | |
} | |
void LoadHistory() | |
{ | |
var strIDrays = EditorPrefs.GetString(MEL_SelectionHistory).Split(char.Parse("|")); | |
this.history.Clear(); | |
sb.Clear(); | |
foreach (var idstrs in strIDrays) | |
{ | |
if (string.IsNullOrEmpty(idstrs)) { continue; } | |
var ids = idstrs.Split(char.Parse(";")).Select(strID => int.Parse(strID)); | |
this.history.Add(ids.ToArray<int>()); | |
} | |
} | |
} | |
public class MLHistoryBackForward : EditorWindow | |
{ | |
[MenuItem("Tools/MLHistory/Show back-forward window")] | |
private static void Init() | |
{ | |
MLHistoryBackForward window = (MLHistoryBackForward)GetWindow(typeof(MLHistoryBackForward)); | |
window.Show(); | |
} | |
void Awake() | |
{ | |
MLHistory.Instance.onStateChanged = () => | |
{ | |
Debug.LogFormat("got state changed"); | |
this.Repaint(); | |
}; | |
} | |
// Ctrl + minus (%-) and Ctrl + shift + minus (%#-) to move forward and back. | |
// Obviously feel free to customize them. | |
// By default Ctrl+minus conflicts with a hierarchy command. (Click resolve | |
// and delete that binding if you want to keep this one.) | |
[MenuItem("Tools/MLHistory/Move Selection Back %-")] | |
private static void MoveBack() | |
{ | |
MLHistory.Instance.moveBack(); | |
} | |
[MenuItem("Tools/MLHistory/Move Selection Forward %#-")] | |
private static void MoveForward() | |
{ | |
MLHistory.Instance.moveForward(); | |
} | |
[MenuItem("Tools/MLHistory/Start tracking if not already")] | |
private static void StartIfNotAlready() | |
{ | |
MLHistory.Instance.Dbug("that should do it"); | |
} | |
void OnGUI() | |
{ | |
EditorGUILayout.BeginHorizontal(); | |
EditorGUI.BeginDisabledGroup(!MLHistory.Instance.isBackAvailable()); | |
if (GUILayout.Button("Back")) | |
{ | |
MLHistory.Instance.moveBack(); | |
} | |
EditorGUI.EndDisabledGroup(); | |
EditorGUI.BeginDisabledGroup(!MLHistory.Instance.isForwardAvailable()); | |
if (GUILayout.Button("Forward")) | |
{ | |
MLHistory.Instance.moveForward(); | |
} | |
EditorGUI.EndDisabledGroup(); | |
EditorGUILayout.EndHorizontal(); | |
} | |
} | |
} | |
// EXTRA CREDIT: make back / forward buttons on the toolbar | |
// depends on: https://github.com/marijnz/unity-toolbar-extender/ | |
// | |
// static class ToolbarStyles | |
// { | |
// public static readonly GUIStyle commandButtonStyle; | |
// static ToolbarStyles() | |
// { | |
// commandButtonStyle = new GUIStyle("Command") | |
// { | |
// fontSize = 16, | |
// alignment = TextAnchor.MiddleCenter, | |
// imagePosition = ImagePosition.ImageAbove, | |
// fontStyle = FontStyle.Bold | |
// }; | |
// } | |
// } | |
// [InitializeOnLoad] | |
// public class MLInitBrowserStyleButtons | |
// { | |
// static MLInitBrowserStyleButtons() { | |
// UnityToolbarExtender.ToolbarExtender.RightToolbarGUI.Add(OnGUIRightToolbar); | |
// } | |
// static void OnGUIRightToolbar() { | |
// GUILayout.FlexibleSpace(); | |
// EditorGUI.BeginDisabledGroup(!MLHistory.Instance.isBackAvailable()); | |
// if (GUILayout.Button("Back")) { | |
// MLHistory.Instance.moveBack(); | |
// } | |
// EditorGUI.EndDisabledGroup(); | |
// EditorGUI.BeginDisabledGroup(!MLHistory.Instance.isForwardAvailable()); | |
// if (GUILayout.Button("Forward")) { | |
// MLHistory.Instance.moveForward(); | |
// } | |
// EditorGUI.EndDisabledGroup(); | |
// } | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment