diff --git a/Source/Editor/Content/Proxy/AnimationGraphFunctionProxy.cs b/Source/Editor/Content/Proxy/AnimationGraphFunctionProxy.cs index c4ea2e09a..a8092a162 100644 --- a/Source/Editor/Content/Proxy/AnimationGraphFunctionProxy.cs +++ b/Source/Editor/Content/Proxy/AnimationGraphFunctionProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Animation/Animation Graph Function")] public class AnimationGraphFunctionProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/AnimationGraphProxy.cs b/Source/Editor/Content/Proxy/AnimationGraphProxy.cs index 3c445c104..7f43b8c7b 100644 --- a/Source/Editor/Content/Proxy/AnimationGraphProxy.cs +++ b/Source/Editor/Content/Proxy/AnimationGraphProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Animation/Animation Graph")] public class AnimationGraphProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/AnimationProxy.cs b/Source/Editor/Content/Proxy/AnimationProxy.cs index bda0fa98d..eb8c892ab 100644 --- a/Source/Editor/Content/Proxy/AnimationProxy.cs +++ b/Source/Editor/Content/Proxy/AnimationProxy.cs @@ -14,6 +14,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Animation/Animation")] public class AnimationProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/CSharpScriptProxy.cs b/Source/Editor/Content/Proxy/CSharpScriptProxy.cs index 332695695..a871d0589 100644 --- a/Source/Editor/Content/Proxy/CSharpScriptProxy.cs +++ b/Source/Editor/Content/Proxy/CSharpScriptProxy.cs @@ -12,6 +12,7 @@ namespace FlaxEditor.Content /// Context proxy object for C# script files. /// /// + [ContentContextMenu("New/C# Script")] public class CSharpScriptProxy : ScriptProxy { /// diff --git a/Source/Editor/Content/Proxy/CollisionDataProxy.cs b/Source/Editor/Content/Proxy/CollisionDataProxy.cs index cca8a8192..b6ff2e75f 100644 --- a/Source/Editor/Content/Proxy/CollisionDataProxy.cs +++ b/Source/Editor/Content/Proxy/CollisionDataProxy.cs @@ -38,6 +38,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Physics/Collision Data")] class CollisionDataProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/CppProxy.cs b/Source/Editor/Content/Proxy/CppProxy.cs index d975b8778..6581dccd2 100644 --- a/Source/Editor/Content/Proxy/CppProxy.cs +++ b/Source/Editor/Content/Proxy/CppProxy.cs @@ -75,6 +75,7 @@ namespace FlaxEditor.Content /// Context proxy object for C++ script files. /// /// + [ContentContextMenu("New/C++/C++ Script")] public class CppScriptProxy : CppProxy { /// @@ -98,6 +99,7 @@ namespace FlaxEditor.Content /// Context proxy object for C++ Json Asset files. /// /// + [ContentContextMenu("New/C++/C++ Function Library")] public class CppStaticClassProxy : CppProxy { /// @@ -115,6 +117,7 @@ namespace FlaxEditor.Content /// Context proxy object for C++ Json Asset files. /// /// + [ContentContextMenu("New/C++/C++ Json Asset")] public class CppAssetProxy : CppProxy { /// diff --git a/Source/Editor/Content/Proxy/GameplayGlobalsProxy.cs b/Source/Editor/Content/Proxy/GameplayGlobalsProxy.cs index 7c8a7268d..af391a8c4 100644 --- a/Source/Editor/Content/Proxy/GameplayGlobalsProxy.cs +++ b/Source/Editor/Content/Proxy/GameplayGlobalsProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Gameplay Globals")] public class GameplayGlobalsProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/JsonAssetProxy.cs b/Source/Editor/Content/Proxy/JsonAssetProxy.cs index 3f2863f74..8bfaae384 100644 --- a/Source/Editor/Content/Proxy/JsonAssetProxy.cs +++ b/Source/Editor/Content/Proxy/JsonAssetProxy.cs @@ -22,6 +22,7 @@ namespace FlaxEditor.Content /// Json assets proxy. /// /// + [ContentContextMenu("New/Json Asset")] public abstract class JsonAssetProxy : JsonAssetBaseProxy { /// diff --git a/Source/Editor/Content/Proxy/MaterialFunctionProxy.cs b/Source/Editor/Content/Proxy/MaterialFunctionProxy.cs index 702f04706..f8c868cb5 100644 --- a/Source/Editor/Content/Proxy/MaterialFunctionProxy.cs +++ b/Source/Editor/Content/Proxy/MaterialFunctionProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Material/Material Function")] public class MaterialFunctionProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/MaterialInstanceProxy.cs b/Source/Editor/Content/Proxy/MaterialInstanceProxy.cs index 663c191ef..60ff9bc51 100644 --- a/Source/Editor/Content/Proxy/MaterialInstanceProxy.cs +++ b/Source/Editor/Content/Proxy/MaterialInstanceProxy.cs @@ -14,6 +14,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Material/Material Instance")] public class MaterialInstanceProxy : BinaryAssetProxy { private MaterialPreview _preview; diff --git a/Source/Editor/Content/Proxy/MaterialProxy.cs b/Source/Editor/Content/Proxy/MaterialProxy.cs index e2e74eb14..68c9c81b7 100644 --- a/Source/Editor/Content/Proxy/MaterialProxy.cs +++ b/Source/Editor/Content/Proxy/MaterialProxy.cs @@ -15,6 +15,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Material/Material")] public class MaterialProxy : BinaryAssetProxy { private MaterialPreview _preview; diff --git a/Source/Editor/Content/Proxy/ParticleEmitterFunctionProxy.cs b/Source/Editor/Content/Proxy/ParticleEmitterFunctionProxy.cs index 24cc22690..b508bb818 100644 --- a/Source/Editor/Content/Proxy/ParticleEmitterFunctionProxy.cs +++ b/Source/Editor/Content/Proxy/ParticleEmitterFunctionProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Particles/Particle Emitter Function")] public class ParticleEmitterFunctionProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/ParticleEmitterProxy.cs b/Source/Editor/Content/Proxy/ParticleEmitterProxy.cs index 089c614da..be07720d2 100644 --- a/Source/Editor/Content/Proxy/ParticleEmitterProxy.cs +++ b/Source/Editor/Content/Proxy/ParticleEmitterProxy.cs @@ -15,6 +15,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Particles/Particle Emitter")] public class ParticleEmitterProxy : BinaryAssetProxy { private ParticleEmitterPreview _preview; diff --git a/Source/Editor/Content/Proxy/ParticleSystemProxy.cs b/Source/Editor/Content/Proxy/ParticleSystemProxy.cs index c19e84a78..38301afdf 100644 --- a/Source/Editor/Content/Proxy/ParticleSystemProxy.cs +++ b/Source/Editor/Content/Proxy/ParticleSystemProxy.cs @@ -39,6 +39,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Particles/Particle System")] public class ParticleSystemProxy : BinaryAssetProxy { private ParticleSystemPreview _preview; diff --git a/Source/Editor/Content/Proxy/PrefabProxy.cs b/Source/Editor/Content/Proxy/PrefabProxy.cs index 64eb1d9f1..a4610b25a 100644 --- a/Source/Editor/Content/Proxy/PrefabProxy.cs +++ b/Source/Editor/Content/Proxy/PrefabProxy.cs @@ -15,6 +15,7 @@ namespace FlaxEditor.Content /// Content proxy for . /// /// + [ContentContextMenu("New/Prefab")] public sealed class PrefabProxy : JsonAssetBaseProxy { private PrefabPreview _preview; diff --git a/Source/Editor/Content/Proxy/SceneProxy.cs b/Source/Editor/Content/Proxy/SceneProxy.cs index 7856fa064..cecd825a1 100644 --- a/Source/Editor/Content/Proxy/SceneProxy.cs +++ b/Source/Editor/Content/Proxy/SceneProxy.cs @@ -10,6 +10,7 @@ namespace FlaxEditor.Content /// Content proxy for . /// /// + [ContentContextMenu("New/Scene")] public sealed class SceneProxy : JsonAssetBaseProxy { /// diff --git a/Source/Editor/Content/Proxy/SettingsProxy.cs b/Source/Editor/Content/Proxy/SettingsProxy.cs index 0bbd2830f..651ba62d2 100644 --- a/Source/Editor/Content/Proxy/SettingsProxy.cs +++ b/Source/Editor/Content/Proxy/SettingsProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// Content proxy for json settings assets (e.g or ). /// /// + [ContentContextMenu("New/Settings")] public class SettingsProxy : JsonAssetProxy { private readonly Type _type; diff --git a/Source/Editor/Content/Proxy/ShaderSourceProxy.cs b/Source/Editor/Content/Proxy/ShaderSourceProxy.cs index 86020c997..9b2ec22d5 100644 --- a/Source/Editor/Content/Proxy/ShaderSourceProxy.cs +++ b/Source/Editor/Content/Proxy/ShaderSourceProxy.cs @@ -13,6 +13,7 @@ namespace FlaxEditor.Content /// Context proxy object for shader source files (represented by ). /// /// + [ContentContextMenu("New/Shader Source")] public class ShaderSourceProxy : ContentProxy { /// diff --git a/Source/Editor/Content/Proxy/SkeletonMaskProxy.cs b/Source/Editor/Content/Proxy/SkeletonMaskProxy.cs index 2a90820b0..ab78a1e09 100644 --- a/Source/Editor/Content/Proxy/SkeletonMaskProxy.cs +++ b/Source/Editor/Content/Proxy/SkeletonMaskProxy.cs @@ -11,6 +11,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Animation/Skeleton Mask")] public class SkeletonMaskProxy : BinaryAssetProxy { /// diff --git a/Source/Editor/Content/Proxy/VisualScriptProxy.cs b/Source/Editor/Content/Proxy/VisualScriptProxy.cs index b065a4fcd..afd105131 100644 --- a/Source/Editor/Content/Proxy/VisualScriptProxy.cs +++ b/Source/Editor/Content/Proxy/VisualScriptProxy.cs @@ -15,6 +15,7 @@ namespace FlaxEditor.Content /// A asset proxy object. /// /// + [ContentContextMenu("New/Visual Script")] public class VisualScriptProxy : BinaryAssetProxy, IScriptTypesContainer { internal VisualScriptProxy() diff --git a/Source/Editor/Windows/ContentWindow.ContextMenu.cs b/Source/Editor/Windows/ContentWindow.ContextMenu.cs index 7368c4efd..56cba9b9e 100644 --- a/Source/Editor/Windows/ContentWindow.ContextMenu.cs +++ b/Source/Editor/Windows/ContentWindow.ContextMenu.cs @@ -39,7 +39,6 @@ namespace FlaxEditor.Windows // Create context menu ContextMenuButton b; - ContextMenuChildMenu c; ContextMenu cm = new ContextMenu { Tag = item @@ -149,22 +148,77 @@ namespace FlaxEditor.Windows { cm.AddButton("New folder", NewFolder); } - - c = cm.AddChildMenu("New"); - c.ContextMenu.Tag = item; - c.ContextMenu.AutoSort = true; - int newItems = 0; - for (int i = 0; i < Editor.ContentDatabase.Proxy.Count; i++) + + // loop through each proxy and user defined json type and add them to the context menu + foreach (var type in Editor.CodeEditing.All.Get()) { - var p = Editor.ContentDatabase.Proxy[i]; + if (type.IsAbstract || !type.HasAttribute(typeof(ContentContextMenuAttribute), true) || Editor.CodeEditing.Actors.Get().Contains(type) || Editor.CodeEditing.Scripts.Get().Contains(type)) + continue; + + ContentContextMenuAttribute attribute = null; + foreach (var typeAttribute in type.GetAttributes(true)) + { + if (typeAttribute is ContentContextMenuAttribute contentContextMenuAttribute) + { + attribute = contentContextMenuAttribute; + break; + } + } + + ContentProxy p; + if (type.Type.IsSubclassOf(typeof(ContentProxy))) + { + p = Editor.ContentDatabase.Proxy.Find(T => T.GetType() == type.Type); + } + else + { + // user can use attribute to put their own assets into the content context menu + var generic = typeof(SpawnableJsonAssetProxy<>).MakeGenericType(type.Type); + var instance = Activator.CreateInstance(generic); + p = instance as AssetProxy; + } + + if (p == null) + continue; + + // create menus if (p.CanCreate(folder)) { - c.ContextMenu.AddButton(p.Name, () => NewItem(p)); - newItems++; + var splitPath = attribute.Path.Split('/'); + ContextMenuChildMenu childCM = null; + bool mainCM = true; + for (int i = 0; i < splitPath?.Length; i++) + { + if (i == splitPath.Length - 1) + { + if (mainCM) + { + cm.AddButton(splitPath[i].Trim(), () => NewItem(p)); + mainCM = false; + } + else + { + childCM?.ContextMenu.AddButton(splitPath[i].Trim(), () => NewItem(p)); + childCM.ContextMenu.AutoSort = true; + } + } + else + { + if (mainCM) + { + childCM = cm.GetOrAddChildMenu(splitPath[i].Trim()); + mainCM = false; + } + else + { + childCM = childCM?.ContextMenu.GetOrAddChildMenu(splitPath[i].Trim()); + } + childCM.ContextMenu.AutoSort = true; + } + } } } - c.Enabled = newItems > 0; - + if (folder.CanHaveAssets) { cm.AddButton("Import file", () => diff --git a/Source/Engine/Physics/PhysicalMaterial.h b/Source/Engine/Physics/PhysicalMaterial.h index 0d8356546..b46c1a294 100644 --- a/Source/Engine/Physics/PhysicalMaterial.h +++ b/Source/Engine/Physics/PhysicalMaterial.h @@ -8,7 +8,7 @@ /// /// Physical materials are used to define the response of a physical object when interacting dynamically with the world. /// -API_CLASS() class FLAXENGINE_API PhysicalMaterial final : public ISerializable +API_CLASS(Attributes = "ContentContextMenu(\"New/Physics/Physical Material\")") class FLAXENGINE_API PhysicalMaterial final : public ISerializable { API_AUTO_SERIALIZATION(); DECLARE_SCRIPTING_TYPE_MINIMAL(PhysicalMaterial); diff --git a/Source/Engine/Scripting/Attributes/Editor/ContentContextMenu.cs b/Source/Engine/Scripting/Attributes/Editor/ContentContextMenu.cs new file mode 100644 index 000000000..ee9956ede --- /dev/null +++ b/Source/Engine/Scripting/Attributes/Editor/ContentContextMenu.cs @@ -0,0 +1,26 @@ +using System; + +namespace FlaxEngine +{ + /// + /// This attribute is used to show content items that can be created in the content browser context menu. Separate the subcontext menus with a /. + /// + [Serializable] + [AttributeUsage(AttributeTargets.Class)] + public class ContentContextMenuAttribute : Attribute + { + /// + /// The path to be used in the context menu + /// + public string Path; + + /// + /// Initializes a new instance of the class. + /// + /// The path to use to create the context menu + public ContentContextMenuAttribute(string path) + { + Path = path; + } + } +}