Instantly share code, notes, and snippets.
Created
September 29, 2021 23:50
-
Save nukadelic/d5c64526c6404d3f3d33ed1b0d41abf9 to your computer and use it in GitHub Desktop.
Unity Context Menu Editor Window
This file contains 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 UnityEngine; | |
using UnityEditor; | |
using System.Reflection; | |
public class ContextMenuEditor : EditorWindow | |
{ | |
[MenuItem("Tools/Edit Context Menu")] static void Init() => GetWindow<ContextMenuEditor>().Show(); | |
System.Type UnityEditorMenuClass; | |
void GetMenuItemDefaultShortcuts(List<string> outItemNames, List<string> outItemDefaultShortcuts) | |
=> UnityEditorMenuClass?.GetMethod("GetMenuItemDefaultShortcuts", BindingFlags.Static | BindingFlags.NonPublic) | |
.Invoke(null, new object[] { outItemNames, outItemDefaultShortcuts }); | |
void RemoveMenuItem(string name) | |
=> UnityEditorMenuClass?.GetMethod("RemoveMenuItem", BindingFlags.Static | BindingFlags.NonPublic) | |
.Invoke(null, new object[] { name }); | |
class Node | |
{ | |
public bool open = false; | |
public bool delete = false; | |
public string name; | |
public string path; | |
public Node parent; | |
public List<Node> children; | |
} | |
List<string> menuItemNames; | |
List<string> menuItemDefaultShortcuts; | |
private void OnEnable() | |
{ | |
UnityEditorMenuClass = null; | |
System.Type[] assemblyTypes = Assembly.GetAssembly(typeof(Editor)).GetTypes(); | |
foreach( var t in assemblyTypes ) if( t.Namespace == "UnityEditor" && t.Name == "Menu" ) UnityEditorMenuClass = t; | |
if (UnityEditorMenuClass == null) { broken = true; return; } | |
FetchMenu(); | |
} | |
void FetchMenu() | |
{ | |
menuItemNames = new List<string>(); | |
menuItemDefaultShortcuts = new List<string>(); | |
GetMenuItemDefaultShortcuts(menuItemNames, menuItemDefaultShortcuts); | |
root = new Node { children = new List<Node>() }; | |
foreach (var path in menuItemNames) | |
{ | |
var node = root; | |
var items = path.Split('/'); | |
foreach (var item in items) | |
{ | |
var found = false; | |
foreach (var n in node.children) | |
{ | |
if (n.name == item) | |
{ | |
found = true; | |
node = n; | |
break; | |
} | |
} | |
if (!found) | |
{ | |
var n = new Node | |
{ | |
children = new List<Node>(), | |
parent = node, | |
name = item, | |
path = path | |
}; | |
node.children.Add(n); | |
node = n; | |
} | |
} | |
} | |
} | |
bool broken = false; | |
Node root; | |
Vector2 scroll; | |
void OnGUI() | |
{ | |
if( broken ) { GUILayout.Label("This is broken, fix me !", EditorStyles.boldLabel); return; } | |
using( var scope = new GUILayout.ScrollViewScope( scroll ) ) | |
{ | |
GUILayout.Space(20); | |
GUILayout.Label( "Context Menu Tree: " , EditorStyles.boldLabel ); | |
foreach (var node in root.children) DrawNode( node ); | |
scroll = scope.scrollPosition; | |
} | |
GUILayout.Space( 10 ); | |
if( GUILayout.Button( "Delete Selected" ) ) | |
{ | |
EachNode( n => | |
{ | |
if( n.delete ) RemoveMenuItem( n.path ); | |
} ); | |
} | |
} | |
void DrawNode( Node node, int intend = 0 ) | |
{ | |
using (new GUILayout.HorizontalScope()) | |
{ | |
GUILayout.Space( intend * 20 ); | |
var content = new GUIContent( node.name, node.path ); | |
if( node.children != null && node.children.Count > 0 ) | |
{ | |
node.open = EditorGUILayout.Foldout( node.open, content ); | |
} | |
else GUILayout.Label( content ); | |
GUILayout.FlexibleSpace(); | |
node.delete = GUILayout.Toggle( node.delete, GUIContent.none ); | |
} | |
if( node.open ) | |
{ | |
if( node.children != null && node.children.Count > 0 ) | |
{ | |
foreach (var child in node.children) | |
{ | |
DrawNode( child , intend + 1 ); | |
} | |
} | |
} | |
} | |
void EachNode(System.Action<Node> callback, Node node = null) | |
{ | |
if (node == null) node = root; | |
foreach (var n in node.children) | |
{ | |
EachNode(callback, n); | |
callback(n); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment