From 7e48786ffc995c93a8a6893ff4c28a6b4a879a41 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Wed, 22 Jul 2026 11:18:32 +0200 Subject: [PATCH] Add type picker when creating abstract class or interface --- .../CustomEditors/Editors/GenericEditor.cs | 49 ++++++++++++++----- Source/Editor/GUI/Popups/TypeSearchPopup.cs | 28 +++++++++++ 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/Source/Editor/CustomEditors/Editors/GenericEditor.cs b/Source/Editor/CustomEditors/Editors/GenericEditor.cs index 900fc6c8d..fb16a1d56 100644 --- a/Source/Editor/CustomEditors/Editors/GenericEditor.cs +++ b/Source/Editor/CustomEditors/Editors/GenericEditor.cs @@ -711,21 +711,44 @@ namespace FlaxEditor.CustomEditors.Editors { // Check if it's an object type that can be created in editor var type = Values.Type; - if (type != ScriptMemberInfo.Null && type.CanCreateInstance) + if (type != ScriptMemberInfo.Null) { - layout = layout.Space(20); - - const float ButtonSize = 14.0f; - var button = new Button + ScriptType[] types = null; + if (type.IsAbstract || type.IsInterface) { - Text = "+", - TooltipText = "Create a new instance of the object", - Size = new Float2(ButtonSize, ButtonSize), - AnchorPreset = AnchorPresets.MiddleRight, - Parent = layout.ContainerControl, - Location = new Float2(layout.ContainerControl.Width - ButtonSize - 4, (layout.ContainerControl.Height - ButtonSize) * 0.5f), - }; - button.Clicked += () => SetValue(Values.Type.CreateInstance()); + // Show picker with all types that implement specific class/interface but are not abstract + types = Editor.Instance.CodeEditing.All.Get().Where(x => !x.IsAbstract && x.CanCreateInstance && type.IsAssignableFrom(x)).ToArray(); + } + else if (type.CanCreateInstance) + { + types = [type]; + } + + if (types != null && types.Length != 0) + { + layout = layout.Space(20); + + const float ButtonSize = 14.0f; + var button = new Button + { + Text = "+", + TooltipText = "Create a new instance of the object", + Size = new Float2(ButtonSize, ButtonSize), + AnchorPreset = AnchorPresets.MiddleRight, + Parent = layout.ContainerControl, + Location = new Float2(layout.ContainerControl.Width - ButtonSize - 4, (layout.ContainerControl.Height - ButtonSize) * 0.5f), + }; + if (types.Length == 1) + { + // Single type + button.Clicked += () => SetValue(Values.Type.CreateInstance()); + } + else + { + // Picker + button.Clicked += () => FlaxEditor.GUI.TypeSearchPopup.Show(button, new Float2(0, button.Height), types, scriptType => { SetValue(scriptType.CreateInstance()); }); + } + } } layout.Label(""); diff --git a/Source/Editor/GUI/Popups/TypeSearchPopup.cs b/Source/Editor/GUI/Popups/TypeSearchPopup.cs index 8d853e66a..85fcccb56 100644 --- a/Source/Editor/GUI/Popups/TypeSearchPopup.cs +++ b/Source/Editor/GUI/Popups/TypeSearchPopup.cs @@ -1,6 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. using System; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using FlaxEditor.History; @@ -131,6 +132,18 @@ namespace FlaxEditor.GUI SortItems(); } + private TypeSearchPopup(IEnumerable items, Action selected) + { + _isValid = null; + _selected = selected; + + ItemClicked += OnItemClicked; + + foreach (var item in items) + AddItem(new TypeItemView(item)); + SortItems(); + } + private bool IsHideAttributes(object[] attributes) { return attributes.FirstOrDefault(IsHideAttribute) == null; @@ -162,6 +175,21 @@ namespace FlaxEditor.GUI return popup; } + /// + /// Shows the popup. + /// + /// The show target. + /// The show target location. + /// Collection of types to display available to pick. + /// Event called on asset item pick. + /// The dialog. + public static TypeSearchPopup Show(Control showTarget, Float2 showTargetLocation, IEnumerable items, Action selected) + { + var popup = new TypeSearchPopup(items, selected); + popup.Show(showTarget, showTargetLocation); + return popup; + } + /// public override void OnDestroy() {