diff --git a/Scripts/Editor/AdvancedGenericMenu.cs b/Scripts/Editor/AdvancedGenericMenu.cs new file mode 100644 index 0000000..549b028 --- /dev/null +++ b/Scripts/Editor/AdvancedGenericMenu.cs @@ -0,0 +1,206 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEditor.IMGUI.Controls; +using UnityEngine; +using static UnityEditor.GenericMenu; + +namespace XNodeEditor +{ + public class AdvancedGenericMenu : AdvancedDropdown + { + private class AdvancedGenericMenuItem : AdvancedDropdownItem + { + private MenuFunction func; + + private MenuFunction2 func2; + private object userData; + + public AdvancedGenericMenuItem( string name ) : base( name ) + { + } + + public AdvancedGenericMenuItem( string name, bool enabled, Texture2D icon, MenuFunction func ) : base( name ) + { + Set( enabled, icon, func ); + } + + public AdvancedGenericMenuItem( string name, bool enabled, Texture2D icon, MenuFunction2 func, object userData ) : base( name ) + { + Set( enabled, icon, func, userData ); + } + + public void Set( bool enabled, Texture2D icon, MenuFunction func ) + { + this.enabled = enabled; + this.icon = icon; + this.func = func; + } + + public void Set( bool enabled, Texture2D icon, MenuFunction2 func, object userData ) + { + this.enabled = enabled; + this.icon = icon; + this.func2 = func; + this.userData = userData; + } + + public void Run() + { + if ( func2 != null ) + func2( userData ); + else if ( func != null ) + func(); + } + } + + private List items = new List(); + + private AdvancedGenericMenuItem FindOrCreateItem( string name, AdvancedGenericMenuItem currentRoot = null ) + { + if ( string.IsNullOrWhiteSpace( name ) ) + return null; + + AdvancedGenericMenuItem item = null; + + string[] paths = name.Split( '/' ); + if ( currentRoot == null ) + { + item = items.FirstOrDefault( x => x != null && x.name == paths[0] ); + if ( item == null ) + items.Add( item = new AdvancedGenericMenuItem( name ) ); + } + else + { + item = currentRoot.children.OfType().FirstOrDefault( x => x.name == paths[0] ); + if ( item == null ) + currentRoot.AddChild( item = new AdvancedGenericMenuItem( name ) ); + } + + if ( paths.Length > 1 ) + return FindOrCreateItem( string.Join( "/", paths, 1, paths.Length - 1 ), item ); + + return item; + } + + private AdvancedGenericMenuItem FindParent( string name ) + { + string[] paths = name.Split( '/' ); + return FindOrCreateItem( string.Join( "/", paths, 0, paths.Length - 1 ) ); + } + + private string Name { get; set; } + + public AdvancedGenericMenu() : base( new AdvancedDropdownState() ) + { + Name = ""; + } + + public AdvancedGenericMenu( string name, AdvancedDropdownState state ) : base( state ) + { + Name = name; + } + + // + // Summary: + // Add a disabled item to the menu. + // + // Parameters: + // content: + // The GUIContent to display as a disabled menu item. + public void AddDisabledItem( GUIContent content ) + { + //var parent = FindParent( content.text ); + var item = FindOrCreateItem( content.text ); + item.Set( false, null, null ); + } + + // + // Summary: + // Add a disabled item to the menu. + // + // Parameters: + // content: + // The GUIContent to display as a disabled menu item. + // + // on: + // Specifies whether to show that the item is currently activated (i.e. a tick next + // to the item in the menu). + public void AddDisabledItem( GUIContent content, bool on ) + { + } + + public void AddItem( string name, bool on, MenuFunction func ) + { + AddItem( new GUIContent( name ), on, func ); + } + + public void AddItem( GUIContent content, bool on, MenuFunction func ) + { + //var parent = FindParent( content.text ); + var item = FindOrCreateItem( content.text ); + item.Set( true/*on*/, null, func ); + } + + public void AddItem( string name, bool on, MenuFunction2 func, object userData ) + { + AddItem( new GUIContent( name ), on, func, userData ); + } + + public void AddItem( GUIContent content, bool on, MenuFunction2 func, object userData ) + { + //var parent = FindParent( content.text ); + var item = FindOrCreateItem( content.text ); + item.Set( true/*on*/, null, func, userData ); + } + + // + // Summary: + // Add a seperator item to the menu. + // + // Parameters: + // path: + // The path to the submenu, if adding a separator to a submenu. When adding a separator + // to the top level of a menu, use an empty string as the path. + public void AddSeparator( string path = null ) + { + var parent = string.IsNullOrWhiteSpace( path ) ? null : FindParent( path ); + if ( parent == null ) + items.Add( null ); + else + parent.AddSeparator(); + } + + // + // Summary: + // Show the menu at the given screen rect. + // + // Parameters: + // position: + // The position at which to show the menu. + public void DropDown( Rect position ) + { + Show( position ); + } + + protected override AdvancedDropdownItem BuildRoot() + { + var root = new AdvancedDropdownItem( Name ); + + foreach ( var m in items ) + { + if ( m == null ) + root.AddSeparator(); + else + root.AddChild( m ); + } + + return root; + } + + protected override void ItemSelected( AdvancedDropdownItem item ) + { + if ( item is AdvancedGenericMenuItem gmItem ) + gmItem.Run(); + } + } +} \ No newline at end of file diff --git a/Scripts/Editor/AdvancedGenericMenu.cs.meta b/Scripts/Editor/AdvancedGenericMenu.cs.meta new file mode 100644 index 0000000..2c5c440 --- /dev/null +++ b/Scripts/Editor/AdvancedGenericMenu.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ddde711109af02e42bfe8eb006577081 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Editor/NodeEditor.cs b/Scripts/Editor/NodeEditor.cs index efe0072..0f92e61 100644 --- a/Scripts/Editor/NodeEditor.cs +++ b/Scripts/Editor/NodeEditor.cs @@ -8,6 +8,9 @@ using Sirenix.OdinInspector.Editor; using Sirenix.Utilities; using Sirenix.Utilities.Editor; #endif +#if USE_ADVANCED_GENERIC_MENU +using GenericMenu = XNodeEditor.AdvancedGenericMenu; +#endif namespace XNodeEditor { /// Base class to derive custom Node editors from. Use this to create your own custom inspectors and editors for your nodes. diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs index b7fb3b4..106590c 100644 --- a/Scripts/Editor/NodeEditorAction.cs +++ b/Scripts/Editor/NodeEditorAction.cs @@ -4,6 +4,9 @@ using System.Linq; using UnityEditor; using UnityEngine; using XNodeEditor.Internal; +#if USE_ADVANCED_GENERIC_MENU +using GenericMenu = XNodeEditor.AdvancedGenericMenu; +#endif namespace XNodeEditor { public partial class NodeEditorWindow { diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs index 70c4cd1..630ad4a 100755 --- a/Scripts/Editor/NodeEditorGUI.cs +++ b/Scripts/Editor/NodeEditorGUI.cs @@ -4,6 +4,9 @@ using System.Linq; using UnityEditor; using UnityEngine; using XNodeEditor.Internal; +#if USE_ADVANCED_GENERIC_MENU +using GenericMenu = XNodeEditor.AdvancedGenericMenu; +#endif namespace XNodeEditor { /// Contains GUI methods diff --git a/Scripts/Editor/NodeEditorReflection.cs b/Scripts/Editor/NodeEditorReflection.cs index 0a0a36a..2069302 100644 --- a/Scripts/Editor/NodeEditorReflection.cs +++ b/Scripts/Editor/NodeEditorReflection.cs @@ -5,6 +5,9 @@ using System.Linq; using System.Reflection; using UnityEditor; using UnityEngine; +#if USE_ADVANCED_GENERIC_MENU +using GenericMenu = XNodeEditor.AdvancedGenericMenu; +#endif namespace XNodeEditor { /// Contains reflection-related extensions built for xNode diff --git a/Scripts/Editor/NodeGraphEditor.cs b/Scripts/Editor/NodeGraphEditor.cs index b6198ca..80b1c1f 100644 --- a/Scripts/Editor/NodeGraphEditor.cs +++ b/Scripts/Editor/NodeGraphEditor.cs @@ -2,6 +2,9 @@ using System.Linq; using UnityEditor; using UnityEngine; +#if USE_ADVANCED_GENERIC_MENU +using GenericMenu = XNodeEditor.AdvancedGenericMenu; +#endif namespace XNodeEditor { /// Base class to derive custom Node Graph editors from. Use this to override how graphs are drawn in the editor.