├── .gitignore ├── Editor.meta ├── Editor ├── Extensions.meta ├── Extensions │ ├── SerializedPropertyExtensions.cs │ ├── SerializedPropertyExtensions.cs.meta │ ├── StringExtensions.cs │ └── StringExtensions.cs.meta ├── Implementation.meta ├── Implementation │ ├── Data.meta │ ├── Data │ │ ├── EditorData.cs │ │ └── EditorData.cs.meta │ ├── Logic.meta │ ├── Logic │ │ ├── GetDefaultTypeIndexLogic.cs │ │ ├── GetDefaultTypeIndexLogic.cs.meta │ │ ├── InitializePropertyAtIndexLogic.cs │ │ ├── InitializePropertyAtIndexLogic.cs.meta │ │ ├── TryCacheNamesGuiContentLogic.cs │ │ ├── TryCacheNamesGuiContentLogic.cs.meta │ │ ├── TryCacheTypesLogic.cs │ │ ├── TryCacheTypesLogic.cs.meta │ │ ├── TryGetTypeIndexLogic.cs │ │ └── TryGetTypeIndexLogic.cs.meta │ ├── SelectImplementationPropertyDrawer.cs │ └── SelectImplementationPropertyDrawer.cs.meta ├── Juce.ImplementationSelector.Editor.asmdef ├── Juce.ImplementationSelector.Editor.asmdef.meta ├── Layout.meta └── Layout │ ├── PropertyDrawerLayoutHelper.cs │ └── PropertyDrawerLayoutHelper.cs.meta ├── Examples.meta ├── Examples ├── Juce.ImplementationSelector.Examples.asmdef ├── Juce.ImplementationSelector.Examples.asmdef.meta ├── Scenes.meta ├── Scenes │ ├── SelectImplementation-InterfaceImplementationExample.unity │ └── SelectImplementation-InterfaceImplementationExample.unity.meta ├── Scripts.meta └── Scripts │ ├── InterfaceImplementation.meta │ └── InterfaceImplementation │ ├── Example1.meta │ ├── Example1 │ ├── IInteraface.cs │ ├── IInteraface.cs.meta │ ├── Implementation1Interface.cs │ ├── Implementation1Interface.cs.meta │ ├── Implementation2Interface.cs │ ├── Implementation2Interface.cs.meta │ ├── Implementation3Interface.cs │ ├── Implementation3Interface.cs.meta │ ├── Implementation4Interface.cs │ ├── Implementation4Interface.cs.meta │ ├── SelectImplementationExample1.cs │ └── SelectImplementationExample1.cs.meta │ ├── Example2.meta │ └── Example2 │ ├── AppleFood.cs │ ├── AppleFood.cs.meta │ ├── GrapesFood.cs │ ├── GrapesFood.cs.meta │ ├── IFood.cs │ ├── IFood.cs.meta │ ├── PizzaFood.cs │ ├── PizzaFood.cs.meta │ ├── SelectImplementationExample2.cs │ └── SelectImplementationExample2.cs.meta ├── LICENSE ├── LICENSE.meta ├── Misc.meta ├── Misc ├── HowTo1.png ├── HowTo1.png.meta ├── HowTo2.png ├── HowTo2.png.meta ├── HowTo3.png ├── HowTo3.png.meta ├── HowTo4.png ├── HowTo4.png.meta ├── HowTo5.png ├── HowTo5.png.meta ├── HowTo6.png └── HowTo6.png.meta ├── README.md ├── README.md.meta ├── Runtime.meta ├── Runtime ├── Implementation.meta ├── Implementation │ ├── SelectImplementationAttribute.cs │ ├── SelectImplementationAttribute.cs.meta │ ├── SelectImplementationCustomDisplayNameAttribute.cs │ ├── SelectImplementationCustomDisplayNameAttribute.cs.meta │ ├── SelectImplementationDefaultTypeAttribute.cs │ ├── SelectImplementationDefaultTypeAttribute.cs.meta │ ├── SelectImplementationTooltipAttribute.cs │ ├── SelectImplementationTooltipAttribute.cs.meta │ ├── SelectImplementationTrimDisplayNameAttribute.cs │ └── SelectImplementationTrimDisplayNameAttribute.cs.meta ├── Juce.ImplementationSelector.Runtime.asmdef └── Juce.ImplementationSelector.Runtime.asmdef.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: da0b54b1b2c211c468b6d2c46a61c5ee 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Extensions.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 165bc736538a52a438a307d0b6bc7a1e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Extensions/SerializedPropertyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | 4 | namespace Juce.ImplementationSelector.Extensions 5 | { 6 | public static class SerializedPropertyExtensions 7 | { 8 | public static float GetVisibleChildHeight(this SerializedProperty serializedProperty) 9 | { 10 | if (!serializedProperty.hasVisibleChildren) 11 | { 12 | return 0; 13 | } 14 | 15 | float height = 0f; 16 | SerializedProperty endProperty = serializedProperty.GetEndProperty(); 17 | 18 | serializedProperty.NextVisible(true); 19 | 20 | while (!SerializedProperty.EqualContents(serializedProperty, endProperty)) 21 | { 22 | height += EditorGUI.GetPropertyHeight(serializedProperty); 23 | serializedProperty.NextVisible(false); 24 | height += EditorGUIUtility.standardVerticalSpacing; 25 | } 26 | 27 | return height; 28 | } 29 | 30 | public static void ForeachVisibleChildren( 31 | this SerializedProperty serializedProperty, 32 | Action action 33 | ) 34 | { 35 | if (!serializedProperty.hasVisibleChildren) 36 | { 37 | return; 38 | } 39 | 40 | SerializedProperty endProperty = serializedProperty.GetEndProperty(); 41 | 42 | serializedProperty.NextVisible(true); 43 | 44 | while (!SerializedProperty.EqualContents(serializedProperty, endProperty)) 45 | { 46 | action.Invoke(serializedProperty); 47 | serializedProperty.NextVisible(false); 48 | } 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /Editor/Extensions/SerializedPropertyExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcaae529e84e1c74491b144c0aaf54fd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace Juce.ImplementationSelector.Extensions 2 | { 3 | public static class StringExtensions 4 | { 5 | public static string RemoveTail(this string source, string tail) 6 | { 7 | if (string.IsNullOrEmpty(tail)) 8 | { 9 | return source; 10 | } 11 | 12 | int index = source.LastIndexOf(tail); 13 | 14 | if (index == -1) 15 | { 16 | return source; 17 | } 18 | 19 | return source.Substring(0, index); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /Editor/Extensions/StringExtensions.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b4500ab8578ef314cba3dac2240a0a01 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e5907a55505a16343b58483c7a39399f 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Implementation/Data.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce63ebf4c69d13a4a8784121b7dbced6 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Implementation/Data/EditorData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace Juce.ImplementationSelector.Data 6 | { 7 | public class EditorData 8 | { 9 | public Type[] Types { get; set; } 10 | public Dictionary TypeIndexMap { get; } = new Dictionary(); 11 | public GUIContent[] NamesGuiContent { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /Editor/Implementation/Data/EditorData.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed067577bc78e5e449e83299cf599674 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation/Logic.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 469e82f39a36e724cbcf8458e81e1b1b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Implementation/Logic/GetDefaultTypeIndexLogic.cs: -------------------------------------------------------------------------------- 1 | using Juce.ImplementationSelector.Data; 2 | using System; 3 | 4 | namespace Juce.ImplementationSelector.Logic 5 | { 6 | public static class GetDefaultTypeIndexLogic 7 | { 8 | public static int Execute( 9 | EditorData editorData 10 | ) 11 | { 12 | for (int i = 0; i < editorData.Types.Length; ++i) 13 | { 14 | Type type = editorData.Types[i]; 15 | 16 | SelectImplementationDefaultTypeAttribute defaultAttribute = Attribute.GetCustomAttribute( 17 | type, 18 | typeof(SelectImplementationDefaultTypeAttribute) 19 | ) as SelectImplementationDefaultTypeAttribute; 20 | 21 | if (defaultAttribute != null) 22 | { 23 | return i; 24 | } 25 | } 26 | 27 | return 0; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /Editor/Implementation/Logic/GetDefaultTypeIndexLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 86366470aaf791247ab2e2b4a72cc532 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation/Logic/InitializePropertyAtIndexLogic.cs: -------------------------------------------------------------------------------- 1 | using Juce.ImplementationSelector.Data; 2 | using System; 3 | using UnityEditor; 4 | using UnityEngine; 5 | 6 | namespace Juce.ImplementationSelector.Logic 7 | { 8 | public static class InitializePropertyAtIndexLogic 9 | { 10 | public static void Execute( 11 | EditorData editorData, 12 | SerializedProperty property, 13 | int typeIndex 14 | ) 15 | { 16 | if(editorData.Types.Length == 0) 17 | { 18 | return; 19 | } 20 | 21 | typeIndex = Mathf.Clamp(typeIndex, 0, editorData.Types.Length - 1); 22 | 23 | Type type = editorData.Types[typeIndex]; 24 | 25 | property.managedReferenceValue = Activator.CreateInstance(type); 26 | property.serializedObject.ApplyModifiedProperties(); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Editor/Implementation/Logic/InitializePropertyAtIndexLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5f5b2df2cce213340bbfbd1dabe24605 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation/Logic/TryCacheNamesGuiContentLogic.cs: -------------------------------------------------------------------------------- 1 | using Juce.ImplementationSelector.Data; 2 | using Juce.ImplementationSelector.Extensions; 3 | using System; 4 | using System.Linq; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Juce.ImplementationSelector.Logic 9 | { 10 | public static class TryCacheNamesGuiContentLogic 11 | { 12 | public static void Execute( 13 | EditorData editorData, 14 | SelectImplementationAttribute typeAttribute 15 | ) 16 | { 17 | if (editorData.NamesGuiContent != null) 18 | { 19 | return; 20 | } 21 | 22 | Type baseType = typeAttribute.FieldType; 23 | 24 | string removeTailString = GetRemoveTailString(baseType); 25 | 26 | editorData.NamesGuiContent = new GUIContent[editorData.Types.Length]; 27 | 28 | for (int i = 0; i < editorData.Types.Length; ++i) 29 | { 30 | Type type = editorData.Types[i]; 31 | 32 | bool hasCustomDisplayName = TryGetCustomDisplayName( 33 | type, 34 | out string customDisplayName 35 | ); 36 | 37 | if (hasCustomDisplayName) 38 | { 39 | editorData.NamesGuiContent[i] = new GUIContent( 40 | ObjectNames.NicifyVariableName(customDisplayName), 41 | GetTypeTooltip(type) 42 | ); 43 | } 44 | else 45 | { 46 | editorData.NamesGuiContent[i] = new GUIContent( 47 | ObjectNames.NicifyVariableName(type.Name.RemoveTail(removeTailString)), 48 | GetTypeTooltip(type) 49 | ); 50 | } 51 | } 52 | } 53 | 54 | private static string GetTypeTooltip(Type type) 55 | { 56 | SelectImplementationTooltipAttribute tooltipAttribute = Attribute.GetCustomAttribute( 57 | type, 58 | typeof(SelectImplementationTooltipAttribute) 59 | ) as SelectImplementationTooltipAttribute; 60 | 61 | if (tooltipAttribute == null) 62 | { 63 | return string.Empty; 64 | } 65 | 66 | return tooltipAttribute.Tooltip; 67 | } 68 | 69 | private static string GetRemoveTailString(Type type) 70 | { 71 | SelectImplementationTrimDisplayNameAttribute trimDisplayNameAttribute 72 | = Attribute.GetCustomAttribute( 73 | type, 74 | typeof(SelectImplementationTrimDisplayNameAttribute) 75 | ) as SelectImplementationTrimDisplayNameAttribute; 76 | 77 | if (trimDisplayNameAttribute == null) 78 | { 79 | return string.Empty; 80 | } 81 | 82 | return trimDisplayNameAttribute.TrimDisplayNameValue; 83 | } 84 | 85 | private static bool TryGetCustomDisplayName( 86 | Type type, 87 | out string customName 88 | ) 89 | { 90 | SelectImplementationCustomDisplayNameAttribute customDisplayNameAttribute 91 | = Attribute.GetCustomAttribute( 92 | type, 93 | typeof(SelectImplementationCustomDisplayNameAttribute) 94 | ) as SelectImplementationCustomDisplayNameAttribute; 95 | 96 | if (customDisplayNameAttribute == null) 97 | { 98 | customName = default; 99 | return false; 100 | } 101 | 102 | customName = customDisplayNameAttribute.CustomDisplayName; 103 | return true; 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /Editor/Implementation/Logic/TryCacheNamesGuiContentLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 333ffbf7e8ff3f54686ff4bca27459f5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation/Logic/TryCacheTypesLogic.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using Juce.ImplementationSelector.Data; 3 | using System; 4 | using System.Linq; 5 | 6 | namespace Juce.ImplementationSelector.Logic 7 | { 8 | public static class TryCacheTypesLogic 9 | { 10 | public static void Execute( 11 | EditorData editorData, 12 | SelectImplementationAttribute typeAttribute 13 | ) 14 | { 15 | if (editorData.Types != null) 16 | { 17 | return; 18 | } 19 | 20 | Type baseType = typeAttribute.FieldType; 21 | 22 | editorData.Types = TypeCache.GetTypesDerivedFrom(baseType).Where(x => 23 | baseType != x && 24 | baseType.IsAssignableFrom(x) && 25 | !x.IsAbstract && 26 | !x.IsSubclassOf(typeof(UnityEngine.Object)) && 27 | (x.GetConstructor(Type.EmptyTypes) != null || x.IsValueType) 28 | ).ToArray(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Editor/Implementation/Logic/TryCacheTypesLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 62c77fb81df87b1409b040bebd0238a9 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation/Logic/TryGetTypeIndexLogic.cs: -------------------------------------------------------------------------------- 1 | using Juce.ImplementationSelector.Data; 2 | using System; 3 | using UnityEditor; 4 | 5 | namespace Juce.ImplementationSelector.Logic 6 | { 7 | public static class TryGetTypeIndexLogic 8 | { 9 | public static bool Execute( 10 | EditorData editorData, 11 | SerializedProperty property, 12 | out int typeIndex 13 | ) 14 | { 15 | string propertyTypeName = property.managedReferenceFullTypename; 16 | 17 | bool typeFound = editorData.TypeIndexMap.TryGetValue( 18 | propertyTypeName, 19 | out typeIndex 20 | ); 21 | 22 | if (typeFound) 23 | { 24 | return true; 25 | } 26 | 27 | for (int i = 0; i < editorData.Types.Length; ++i) 28 | { 29 | Type type = editorData.Types[i]; 30 | 31 | string fullTypename = type.FullName; 32 | 33 | if (propertyTypeName.Contains(fullTypename)) 34 | { 35 | editorData.TypeIndexMap.Add(propertyTypeName, i); 36 | return true; 37 | } 38 | } 39 | 40 | return false; 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /Editor/Implementation/Logic/TryGetTypeIndexLogic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 97108865ced0e9743a7fed914e403f92 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Implementation/SelectImplementationPropertyDrawer.cs: -------------------------------------------------------------------------------- 1 | using Juce.ImplementationSelector.Data; 2 | using Juce.ImplementationSelector.Extensions; 3 | using Juce.ImplementationSelector.Layout; 4 | using Juce.ImplementationSelector.Logic; 5 | using UnityEditor; 6 | using UnityEngine; 7 | 8 | namespace Juce.ImplementationSelector 9 | { 10 | [CustomPropertyDrawer(typeof(SelectImplementationAttribute))] 11 | public class SelectImplementationPropertyDrawer : PropertyDrawer 12 | { 13 | private readonly PropertyDrawerLayoutHelper layoutHelper = new PropertyDrawerLayoutHelper(); 14 | 15 | private readonly EditorData editorData = new EditorData(); 16 | 17 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label) 18 | { 19 | SelectImplementationAttribute typeAttribute = (SelectImplementationAttribute)attribute; 20 | 21 | float height = layoutHelper.GetElementsHeight(1); 22 | 23 | bool isCollapsed = !property.isExpanded && !typeAttribute.ForceExpanded; 24 | 25 | if (isCollapsed) 26 | { 27 | return height; 28 | } 29 | 30 | return height + property.GetVisibleChildHeight(); 31 | } 32 | 33 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 34 | { 35 | SelectImplementationAttribute typeAttribute = (SelectImplementationAttribute)attribute; 36 | 37 | TryCacheTypesLogic.Execute(editorData, typeAttribute); 38 | TryCacheNamesGuiContentLogic.Execute(editorData, typeAttribute); 39 | 40 | bool typeIndexFound = TryGetTypeIndexLogic.Execute( 41 | editorData, 42 | property, 43 | out int typeIndex 44 | ); 45 | 46 | bool isUninitalized = !typeIndexFound && editorData.Types.Length > 0; 47 | 48 | if (isUninitalized) 49 | { 50 | typeIndex = GetDefaultTypeIndexLogic.Execute(editorData); 51 | 52 | InitializePropertyAtIndexLogic.Execute( 53 | editorData, 54 | property, 55 | typeIndex 56 | ); 57 | } 58 | 59 | if (Event.current.type == EventType.Layout) 60 | { 61 | return; 62 | } 63 | 64 | layoutHelper.Init(position); 65 | 66 | bool shouldDrawChildren = (property.hasVisibleChildren && property.isExpanded) || typeAttribute.ForceExpanded; 67 | 68 | Rect popupRect = layoutHelper.NextVerticalRect(); 69 | 70 | GUIContent finalLabel = GUIContent.none; 71 | 72 | if (typeAttribute.DisplayLabel) 73 | { 74 | finalLabel = label; 75 | } 76 | 77 | if (typeAttribute.ForceExpanded) 78 | { 79 | property.isExpanded = true; 80 | } 81 | else 82 | { 83 | property.isExpanded = EditorGUI.Foldout(popupRect, property.isExpanded, GUIContent.none); 84 | } 85 | 86 | int newTypeIndex = EditorGUI.Popup( 87 | popupRect, 88 | finalLabel, 89 | typeIndex, 90 | editorData.NamesGuiContent 91 | ); 92 | 93 | if (newTypeIndex != typeIndex) 94 | { 95 | InitializePropertyAtIndexLogic.Execute( 96 | editorData, 97 | property, 98 | newTypeIndex 99 | ); 100 | } 101 | 102 | if (!shouldDrawChildren && !property.isExpanded) 103 | { 104 | return; 105 | } 106 | 107 | EditorGUI.indentLevel++; 108 | { 109 | property.ForeachVisibleChildren(DrawChildPropertyField); 110 | } 111 | EditorGUI.indentLevel--; 112 | } 113 | 114 | private void DrawChildPropertyField(SerializedProperty childProperty) 115 | { 116 | EditorGUI.PropertyField( 117 | layoutHelper.NextVerticalRect(childProperty), 118 | childProperty, 119 | includeChildren: true 120 | ); 121 | } 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /Editor/Implementation/SelectImplementationPropertyDrawer.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 504174a19ff82b14e8ede98a903e8c95 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Editor/Juce.ImplementationSelector.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Juce.ImplementationSelector.Editor", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:1089a22bce0ea9a468bf8e5a4f8cbad5" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /Editor/Juce.ImplementationSelector.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1bbc05c702b8f424a87904fc5cab75c9 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/Layout.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36d540ed6a84efc48b67f870f292bac4 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Editor/Layout/PropertyDrawerLayoutHelper.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | 3 | using UnityEngine; 4 | 5 | namespace Juce.ImplementationSelector.Layout 6 | { 7 | public class PropertyDrawerLayoutHelper 8 | { 9 | private Rect totalRect; 10 | private Rect currentRect; 11 | 12 | private bool isFirst; 13 | 14 | public Rect TotalRect => totalRect; 15 | 16 | public void Init(Rect rect) 17 | { 18 | this.totalRect = new Rect(rect.position, Vector2.zero); 19 | this.currentRect = rect; 20 | 21 | this.isFirst = true; 22 | } 23 | 24 | public Rect NextVerticalRect(float height) 25 | { 26 | currentRect.height = height; 27 | 28 | if (!isFirst) 29 | { 30 | height += 2f; 31 | currentRect.y = totalRect.y + totalRect.height + 2.0f; 32 | } 33 | 34 | totalRect.height += height; 35 | 36 | isFirst = false; 37 | 38 | return currentRect; 39 | } 40 | 41 | public Rect NextVerticalRect() 42 | { 43 | return NextVerticalRect(EditorGUIUtility.singleLineHeight); 44 | } 45 | 46 | public Rect NextVerticalRect(SerializedProperty serializedProperty) 47 | { 48 | return NextVerticalRect(EditorGUI.GetPropertyHeight(serializedProperty)); 49 | } 50 | 51 | public float GetElementsHeight(int elementsCount) 52 | { 53 | if (elementsCount <= 0) 54 | { 55 | return 0f; 56 | } 57 | 58 | return (elementsCount * (EditorGUIUtility.singleLineHeight + 2)) + 2; 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /Editor/Layout/PropertyDrawerLayoutHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6b608d3eb8e43ce458dd41292626b33c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d14e66cfd03a4ef4e89df1beabd585af 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Examples/Juce.ImplementationSelector.Examples.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Juce.ImplementationSelector.Examples", 3 | "rootNamespace": "", 4 | "references": [ 5 | "GUID:1089a22bce0ea9a468bf8e5a4f8cbad5" 6 | ], 7 | "includePlatforms": [], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Examples/Juce.ImplementationSelector.Examples.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7844bfcd4a003c429b2b3a82de4167b 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Examples/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e2f62a902c22ae64ab013fa0f94906d9 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Examples/Scenes/SelectImplementation-InterfaceImplementationExample.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0.37311953, g: 0.38074014, b: 0.3587274, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 12 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 0 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 1 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 512 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 256 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 1 83 | m_PVRDenoiserTypeDirect: 1 84 | m_PVRDenoiserTypeIndirect: 1 85 | m_PVRDenoiserTypeAO: 1 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 1 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightProbeSampleCountMultiplier: 4 100 | m_LightingDataAsset: {fileID: 0} 101 | m_LightingSettings: {fileID: 0} 102 | --- !u!196 &4 103 | NavMeshSettings: 104 | serializedVersion: 2 105 | m_ObjectHideFlags: 0 106 | m_BuildSettings: 107 | serializedVersion: 2 108 | agentTypeID: 0 109 | agentRadius: 0.5 110 | agentHeight: 2 111 | agentSlope: 45 112 | agentClimb: 0.4 113 | ledgeDropHeight: 0 114 | maxJumpAcrossDistance: 0 115 | minRegionArea: 2 116 | manualCellSize: 0 117 | cellSize: 0.16666667 118 | manualTileSize: 0 119 | tileSize: 256 120 | accuratePlacement: 0 121 | maxJobWorkers: 0 122 | preserveTilesOutsideBounds: 0 123 | debug: 124 | m_Flags: 0 125 | m_NavMeshData: {fileID: 0} 126 | --- !u!1 &147638381 127 | GameObject: 128 | m_ObjectHideFlags: 0 129 | m_CorrespondingSourceObject: {fileID: 0} 130 | m_PrefabInstance: {fileID: 0} 131 | m_PrefabAsset: {fileID: 0} 132 | serializedVersion: 6 133 | m_Component: 134 | - component: {fileID: 147638383} 135 | - component: {fileID: 147638382} 136 | m_Layer: 0 137 | m_Name: Example2 138 | m_TagString: Untagged 139 | m_Icon: {fileID: 0} 140 | m_NavMeshLayer: 0 141 | m_StaticEditorFlags: 0 142 | m_IsActive: 1 143 | --- !u!114 &147638382 144 | MonoBehaviour: 145 | m_ObjectHideFlags: 0 146 | m_CorrespondingSourceObject: {fileID: 0} 147 | m_PrefabInstance: {fileID: 0} 148 | m_PrefabAsset: {fileID: 0} 149 | m_GameObject: {fileID: 147638381} 150 | m_Enabled: 1 151 | m_EditorHideFlags: 0 152 | m_Script: {fileID: 11500000, guid: 47019c2795620594fa59a1e78151b88c, type: 3} 153 | m_Name: 154 | m_EditorClassIdentifier: 155 | food: 156 | id: 0 157 | references: 158 | version: 1 159 | 00000000: 160 | type: {class: PizzaFood, ns: Juce.ImplementationSelector.Example2, asm: Juce.ImplementationSelector.Examples} 161 | data: 162 | pizzaType: 163 | ammountOfSlices: 0 164 | --- !u!4 &147638383 165 | Transform: 166 | m_ObjectHideFlags: 0 167 | m_CorrespondingSourceObject: {fileID: 0} 168 | m_PrefabInstance: {fileID: 0} 169 | m_PrefabAsset: {fileID: 0} 170 | m_GameObject: {fileID: 147638381} 171 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 172 | m_LocalPosition: {x: 0, y: 0, z: 0} 173 | m_LocalScale: {x: 1, y: 1, z: 1} 174 | m_Children: [] 175 | m_Father: {fileID: 0} 176 | m_RootOrder: 1 177 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 178 | --- !u!1 &272724071 179 | GameObject: 180 | m_ObjectHideFlags: 0 181 | m_CorrespondingSourceObject: {fileID: 0} 182 | m_PrefabInstance: {fileID: 0} 183 | m_PrefabAsset: {fileID: 0} 184 | serializedVersion: 6 185 | m_Component: 186 | - component: {fileID: 272724073} 187 | - component: {fileID: 272724072} 188 | m_Layer: 0 189 | m_Name: Example1 190 | m_TagString: Untagged 191 | m_Icon: {fileID: 0} 192 | m_NavMeshLayer: 0 193 | m_StaticEditorFlags: 0 194 | m_IsActive: 1 195 | --- !u!114 &272724072 196 | MonoBehaviour: 197 | m_ObjectHideFlags: 0 198 | m_CorrespondingSourceObject: {fileID: 0} 199 | m_PrefabInstance: {fileID: 0} 200 | m_PrefabAsset: {fileID: 0} 201 | m_GameObject: {fileID: 272724071} 202 | m_Enabled: 1 203 | m_EditorHideFlags: 0 204 | m_Script: {fileID: 11500000, guid: 49d1d29919ff9c74ca71aa91f591fe37, type: 3} 205 | m_Name: 206 | m_EditorClassIdentifier: 207 | listImplementations: 208 | - id: 0 209 | listForceExpandImplementations: 210 | - id: 1 211 | listForceExpandNoLabelImplementations: 212 | - id: 2 213 | singleImplementation: 214 | id: 3 215 | singleForceExpandImplementation: 216 | id: 4 217 | singleForceExpandNoLabelImplementation: 218 | id: 5 219 | references: 220 | version: 1 221 | 00000000: 222 | type: {class: Implementation2Interface, ns: Juce.ImplementationSelector.Example1, asm: Juce.ImplementationSelector.Examples} 223 | data: 224 | stringValue: 225 | 00000001: 226 | type: {class: Implementation2Interface, ns: Juce.ImplementationSelector.Example1, asm: Juce.ImplementationSelector.Examples} 227 | data: 228 | stringValue: 229 | 00000002: 230 | type: {class: Implementation2Interface, ns: Juce.ImplementationSelector.Example1, asm: Juce.ImplementationSelector.Examples} 231 | data: 232 | stringValue: 233 | 00000003: 234 | type: {class: Implementation2Interface, ns: Juce.ImplementationSelector.Example1, asm: Juce.ImplementationSelector.Examples} 235 | data: 236 | stringValue: 237 | 00000004: 238 | type: {class: Implementation2Interface, ns: Juce.ImplementationSelector.Example1, asm: Juce.ImplementationSelector.Examples} 239 | data: 240 | stringValue: 241 | 00000005: 242 | type: {class: Implementation2Interface, ns: Juce.ImplementationSelector.Example1, asm: Juce.ImplementationSelector.Examples} 243 | data: 244 | stringValue: 245 | --- !u!4 &272724073 246 | Transform: 247 | m_ObjectHideFlags: 0 248 | m_CorrespondingSourceObject: {fileID: 0} 249 | m_PrefabInstance: {fileID: 0} 250 | m_PrefabAsset: {fileID: 0} 251 | m_GameObject: {fileID: 272724071} 252 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 253 | m_LocalPosition: {x: 0, y: 0, z: 0} 254 | m_LocalScale: {x: 1, y: 1, z: 1} 255 | m_Children: [] 256 | m_Father: {fileID: 0} 257 | m_RootOrder: 0 258 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 259 | -------------------------------------------------------------------------------- /Examples/Scenes/SelectImplementation-InterfaceImplementationExample.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2256e1e42c67ce84e990ff4386b9f89a 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Examples/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f2ca0b3545602b94eada4cd942f99b26 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e08f73300d6c35441abb516b0b4c6666 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b78da1c253a714541a131d7c87247957 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/IInteraface.cs: -------------------------------------------------------------------------------- 1 | namespace Juce.ImplementationSelector.Example1 2 | { 3 | [SelectImplementationTrimDisplayName("Interface")] 4 | public interface IInteraface 5 | { 6 | 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/IInteraface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: db48679b5fe51fa438e7e87d7271ef79 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation1Interface.cs: -------------------------------------------------------------------------------- 1 | namespace Juce.ImplementationSelector.Example1 2 | { 3 | [System.Serializable] 4 | [SelectImplementationCustomDisplayName("Custom display")] 5 | public class Implementation1Interface : IInteraface 6 | { 7 | public int intValue = default; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation1Interface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 98d07e5a4ec4e5343a6fbb8b527122c3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation2Interface.cs: -------------------------------------------------------------------------------- 1 | namespace Juce.ImplementationSelector.Example1 2 | { 3 | [System.Serializable] 4 | [SelectImplementationDefaultType] 5 | public class Implementation2Interface : IInteraface 6 | { 7 | public string stringValue = default; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation2Interface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 43edeef39558ced46920672ce596e689 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation3Interface.cs: -------------------------------------------------------------------------------- 1 | namespace Juce.ImplementationSelector.Example1 2 | { 3 | [System.Serializable] 4 | [SelectImplementationTooltip("Test tooltip")] 5 | public class Implementation3Interface : IInteraface 6 | { 7 | public float floatValue = default; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation3Interface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 22130aea7a747d240bb204e20f53d813 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation4Interface.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector.Example1 5 | { 6 | [System.Serializable] 7 | [SelectImplementationCustomDisplayName("Nested")] 8 | public class Implementation4Interface : IInteraface 9 | { 10 | [SelectImplementation(typeof(IInteraface))] 11 | [SerializeField, SerializeReference] private List listImplementations = new List(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/Implementation4Interface.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 89cde107a3a151a4f873c8c1594f98b4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/SelectImplementationExample1.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector.Example1 5 | { 6 | public class SelectImplementationExample1 : MonoBehaviour 7 | { 8 | [SelectImplementation(typeof(IInteraface))] 9 | [SerializeField, SerializeReference] private List listImplementations = new List(); 10 | 11 | [SelectImplementation(typeof(IInteraface), displayLabel: true, forceExpanded: true)] 12 | [SerializeField, SerializeReference] private List listForceExpandImplementations = new List(); 13 | 14 | [SelectImplementation(typeof(IInteraface), displayLabel: false, forceExpanded: true)] 15 | [SerializeField, SerializeReference] private List listForceExpandNoLabelImplementations = new List(); 16 | 17 | [Header("SingleImplementation")] 18 | [SelectImplementation(typeof(IInteraface))] 19 | [SerializeField, SerializeReference] private IInteraface singleImplementation = new Implementation2Interface(); 20 | 21 | [Header("SingleForceExpandImplementation")] 22 | [SelectImplementation(typeof(IInteraface), displayLabel: true, forceExpanded: true)] 23 | [SerializeField, SerializeReference] private IInteraface singleForceExpandImplementation = new Implementation2Interface(); 24 | 25 | [Header("SingleForceExpandNoLabelImplementation")] 26 | [SelectImplementation(typeof(IInteraface), displayLabel: false, forceExpanded: true)] 27 | [SerializeField, SerializeReference] 28 | private IInteraface singleForceExpandNoLabelImplementation = new Implementation2Interface(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example1/SelectImplementationExample1.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 49d1d29919ff9c74ca71aa91f591fe37 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5767d199aea4c9d40a41402a2bd243dd 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/AppleFood.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector.Example2 5 | { 6 | [SelectImplementationDefaultType] 7 | [System.Serializable] 8 | public class AppleFood : IFood 9 | { 10 | [SerializeField] 11 | private string appleName = default; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/AppleFood.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6424a3403968d6e4ca71befd3992b150 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/GrapesFood.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector.Example2 5 | { 6 | [System.Serializable] 7 | public class GrapesFood : IFood 8 | { 9 | [SerializeField, Min(0)] private int ammountOfGrapes = default; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/GrapesFood.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ff733b62f32cfd546b88151b70146b67 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/IFood.cs: -------------------------------------------------------------------------------- 1 | namespace Juce.ImplementationSelector.Example2 2 | { 3 | [SelectImplementationTrimDisplayName("Food")] 4 | public interface IFood 5 | { 6 | 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/IFood.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5bbec93bc98edce43bfb16b40a31a5b5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/PizzaFood.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector.Example2 5 | { 6 | [System.Serializable] 7 | public class PizzaFood : IFood 8 | { 9 | [SerializeField, Min(0)] private string pizzaType = default; 10 | [SerializeField, Min(0)] private int ammountOfSlices = default; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/PizzaFood.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: be0f88b35f7767648a9148c7ebd2a308 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/SelectImplementationExample2.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector.Example2 5 | { 6 | public class SelectImplementationExample2 : MonoBehaviour 7 | { 8 | [SelectImplementation(typeof(IFood))] 9 | [SerializeField, SerializeReference] 10 | private IFood food = default; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Examples/Scripts/InterfaceImplementation/Example2/SelectImplementationExample2.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 47019c2795620594fa59a1e78151b88c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Juce Assets 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 06d0c8c2bb2143c40a18497cdb3ab314 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Misc.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f5e860b1492bc4d43967a1d3dfd484df 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Misc/HowTo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillemsc/ImplementationSelector/8ec8e972e1f389ee912bffa016a6c2df7f57a4e8/Misc/HowTo1.png -------------------------------------------------------------------------------- /Misc/HowTo1.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1df7069bc83929d489600b765e8d5826 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /Misc/HowTo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillemsc/ImplementationSelector/8ec8e972e1f389ee912bffa016a6c2df7f57a4e8/Misc/HowTo2.png -------------------------------------------------------------------------------- /Misc/HowTo2.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ea3b6ee037a2b6d41987752a53d37fed 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /Misc/HowTo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillemsc/ImplementationSelector/8ec8e972e1f389ee912bffa016a6c2df7f57a4e8/Misc/HowTo3.png -------------------------------------------------------------------------------- /Misc/HowTo3.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5de88093bb21861468a07a12ce47fb20 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /Misc/HowTo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillemsc/ImplementationSelector/8ec8e972e1f389ee912bffa016a6c2df7f57a4e8/Misc/HowTo4.png -------------------------------------------------------------------------------- /Misc/HowTo4.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 674635cc0de9812468c9b8dedb2cc94f 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /Misc/HowTo5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillemsc/ImplementationSelector/8ec8e972e1f389ee912bffa016a6c2df7f57a4e8/Misc/HowTo5.png -------------------------------------------------------------------------------- /Misc/HowTo5.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d0bb47495a4afc44f92556425b0b09a8 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /Misc/HowTo6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guillemsc/ImplementationSelector/8ec8e972e1f389ee912bffa016a6c2df7f57a4e8/Misc/HowTo6.png -------------------------------------------------------------------------------- /Misc/HowTo6.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2384cabff4ff75b4999f2da6c57470ad 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 11 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | grayScaleToAlpha: 0 28 | generateCubemap: 6 29 | cubemapConvolution: 0 30 | seamlessCubemap: 0 31 | textureFormat: 1 32 | maxTextureSize: 2048 33 | textureSettings: 34 | serializedVersion: 2 35 | filterMode: 1 36 | aniso: 1 37 | mipBias: 0 38 | wrapU: 0 39 | wrapV: 0 40 | wrapW: 0 41 | nPOTScale: 1 42 | lightmap: 0 43 | compressionQuality: 50 44 | spriteMode: 0 45 | spriteExtrude: 1 46 | spriteMeshType: 1 47 | alignment: 0 48 | spritePivot: {x: 0.5, y: 0.5} 49 | spritePixelsToUnits: 100 50 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 51 | spriteGenerateFallbackPhysicsShape: 1 52 | alphaUsage: 1 53 | alphaIsTransparency: 0 54 | spriteTessellationDetail: -1 55 | textureType: 0 56 | textureShape: 1 57 | singleChannelComponent: 0 58 | flipbookRows: 1 59 | flipbookColumns: 1 60 | maxTextureSizeSet: 0 61 | compressionQualitySet: 0 62 | textureFormatSet: 0 63 | ignorePngGamma: 0 64 | applyGammaDecoding: 0 65 | platformSettings: 66 | - serializedVersion: 3 67 | buildTarget: DefaultTexturePlatform 68 | maxTextureSize: 2048 69 | resizeAlgorithm: 0 70 | textureFormat: -1 71 | textureCompression: 1 72 | compressionQuality: 50 73 | crunchedCompression: 0 74 | allowsAlphaSplitting: 0 75 | overridden: 0 76 | androidETC2FallbackOverride: 0 77 | forceMaximumCompressionQuality_BC6H_BC7: 0 78 | spriteSheet: 79 | serializedVersion: 2 80 | sprites: [] 81 | outline: [] 82 | physicsShape: [] 83 | bones: [] 84 | spriteID: 85 | internalID: 0 86 | vertices: [] 87 | indices: 88 | edges: [] 89 | weights: [] 90 | secondaryTextures: [] 91 | spritePackingTag: 92 | pSDRemoveMatte: 0 93 | pSDShowRemoveMatteOption: 0 94 | userData: 95 | assetBundleName: 96 | assetBundleVariant: 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Implementation Selector 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT) 4 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/Juce-Assets/Juce-ImplementationSelector/issues) 5 | [![Twitter Follow](https://img.shields.io/badge/twitter-%406uillem-blue.svg?style=flat&label=Follow)](https://twitter.com/6uillem) 6 | [![Release](https://img.shields.io/github/release/Juce-Assets/Juce-ImplementationSelector.svg)](https://github.com/Juce-Assets/Juce-ImplementationSelector/releases/latest) 7 | 8 | **Welcome to [Implementation Selector](https://github.com/Juce-Assets/Juce-ImplementationSelector):** a small Unity editor extension that allows you to automatically select an interface/base class's implementations directly on the editor. This is very useful for rapdily create configuration files for your applications. 9 | 10 | Logo 11 | 12 | # Contents 13 | 14 | - [Installing](https://github.com/Juce-Assets/Juce-ImplementationSelector#installing) 15 | - [Basic Usage](https://github.com/Juce-Assets/Juce-ImplementationSelector#basic-usage) 16 | - [Want to contribute?](https://github.com/Juce-Assets/Juce-ImplementationSelector#want-to-contribute) 17 | - [Contributors](https://github.com/Juce-Assets/Juce-ImplementationSelector#contributors) 18 | 19 | ## Installing 20 | ### - Via Github 21 | Download the full repositories, and then place it under the Assets folder of your Unity project. 22 | 23 | And that's all, with that you should be ready to go! 24 | 25 | ### - Via UPM 26 | Add the following line to your [manifest.json](https://docs.unity3d.com/Manual/upm-manifestPrj.html). 27 | ``` 28 | "dependencies": { 29 | "com.juce.implementationselector": "git+https://github.com/Juce-Assets/Juce-ImplementationSelector", 30 | }, 31 | ``` 32 | 33 | ## Basic Usage 34 | ### - SelectImplementationAttribute 35 | You can turn an interface/base class to a selectable one using the attribute SelectImplementationAttribute. 36 | You also need to use the SerializeReference Unity attribute. 37 | ```csharp 38 | [SelectImplementation(typeof(IFood))] 39 | [SerializeField, SerializeReference] private IFood food = default; 40 | ``` 41 | 42 | Logo 43 | 44 | Logo 45 | 46 | Logo 47 | 48 | It works with lists too! 49 | ```csharp 50 | [SelectImplementation(typeof(IFood))] 51 | [SerializeField, SerializeReference] private List food = default; 52 | ``` 53 | Logo 54 | 55 | SelectImplementation has two default values that can be changed: 56 | - DisplayLabel: determines if the variable name is shown on the inspector. It's enabled by default. 57 | - ForceExpanded: determines if the properties of the class can be collapsed with a dropdown, or ar shown all the time. It's disabled by default. 58 | ```csharp 59 | [SelectImplementation(typeof(IFood), displayLabel: true, forceExpanded: false)] 60 | [SerializeField, SerializeReference] private IFood food = default; 61 | ``` 62 | 63 | The classes that inherit from the base one need to be marked as serializable with the System.Serializable attribute. 64 | They also need to have the default constructor, or a public parameterless one. 65 | ```csharp 66 | [System.Serializable] 67 | public class AppleFood : IFood 68 | { 69 | [SerializeField] private string appleName = default; 70 | } 71 | ``` 72 | 73 |   74 | 75 | ### - SelectImplementationTrimDisplayName 76 | You can use the attribute SelectImplementationTrimDisplayName, on the base interface/class, to define a string that will always be trimmed from the name displayed of the classes that implement this interface. 77 | 78 | For example, if you have a base interface named IFood, and classes that inherit from it, like AppleFood, GrapesFood, PizzaFood, by using the SelectImplementationTrimDisplayName("Food"), the class names will be desplayed as Apple, Grapes, Pizza. 79 | ```csharp 80 | [SelectImplementationTrimDisplayName("Food")] 81 | public interface IFood 82 | { 83 | 84 | } 85 | ``` 86 | 87 |   88 | 89 | ### - SelectImplementationDefaultType 90 | You can use the attribute SelectImplementationDefaultType, on one of the classes that inherits from the base interface/class, to mark it as the default one that's going to appear on the editor the first time the user sees it. 91 | ```csharp 92 | [System.Serializable] 93 | [SelectImplementationDefaultType] 94 | public class AppleFood : IFood 95 | { 96 | [SerializeField] private string appleName = default; 97 | } 98 | ``` 99 | 100 |   101 | 102 | ### - SelectImplementationTooltip 103 | You can use the attribute SelectImplementationTooltip, on one of the classes that inherits from the base interface/class, to show a tooltip when the user hovers this specific type with the mouse 104 | ```csharp 105 | [System.Serializable] 106 | [SelectImplementationTooltip("Apple tooltip")] 107 | public class AppleFood : IFood 108 | { 109 | [SerializeField] private string appleName = default; 110 | } 111 | ``` 112 | Logo 113 | 114 |   115 | 116 | ### - SelectImplementationCustomDisplayName 117 | You can use the attribute SelectImplementationCustomDisplayName, on one of the classes that inherits from the base interface/class, to show a specific name on the selection dropdown. 118 | ```csharp 119 | [System.Serializable] 120 | [SelectImplementationCustomDisplayName("Custom Apple display")] 121 | public class AppleFood : IFood 122 | { 123 | [SerializeField] private string appleName = default; 124 | } 125 | ``` 126 | Logo 127 | 128 | 129 | #### We are always aiming to improve this tool. You can always leave suggestions [here](https://github.com/Juce-Assets/Juce-ImplementationSelector/issues). 130 | 131 | ## Want to contribute? 132 | 133 | **Please follow these steps to get your work merged in.** 134 | 135 | 0. Clone the repo and make a new branch: `$ git checkout https://github.com/Juce-Assets/Juce-ImplementationSelector/tree/main -b [name_of_new_branch]`. 136 | 137 | 1. Add a feature, fix a bug, or refactor some code :) 138 | 139 | 2. Update `README.md` contributors, if necessary. 140 | 141 | 3. Open a Pull Request with a comprehensive description of changes. 142 | 143 | ### 144 | 145 | ## Contributors 146 | 147 | - Guillem SC - [@Guillemsc](https://github.com/Guillemsc) 148 | - Pere Viader - [@PereViader](https://github.com/PereViader) 149 | - Balázs K - [@BallerJColt](https://github.com/BallerJColt) 150 | - IvanPolovyi - [@IvanPolovyi](https://github.com/IvanPolovyi) 151 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2500b2932c56deb4bb5ccb0aae835668 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1bc3a6211e25ae44daf0fa57d30c192a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Implementation.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1fbc4e86dd78e1b4289d094cb5953c9e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEngine; 3 | 4 | namespace Juce.ImplementationSelector 5 | { 6 | public class SelectImplementationAttribute : PropertyAttribute 7 | { 8 | public Type FieldType { get; } 9 | public bool DisplayLabel { get; } 10 | public bool ForceExpanded { get; } 11 | 12 | public SelectImplementationAttribute( 13 | Type type, 14 | bool displayLabel = true, 15 | bool forceExpanded = false 16 | ) 17 | { 18 | FieldType = type; 19 | DisplayLabel = displayLabel; 20 | ForceExpanded = forceExpanded; 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b7ded4855d6a9da4980c55a0bdfaba77 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationCustomDisplayNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Juce.ImplementationSelector 4 | { 5 | public class SelectImplementationCustomDisplayNameAttribute : Attribute 6 | { 7 | public string CustomDisplayName { get; } 8 | 9 | public SelectImplementationCustomDisplayNameAttribute(string customDisplayName) 10 | { 11 | CustomDisplayName = customDisplayName; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationCustomDisplayNameAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fb7257948419e7245b87c2f6ce03bbe2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationDefaultTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Juce.ImplementationSelector 4 | { 5 | public class SelectImplementationDefaultTypeAttribute : Attribute 6 | { 7 | public SelectImplementationDefaultTypeAttribute() 8 | { 9 | 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationDefaultTypeAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 499fde75d7cceca41a74992d19b56240 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationTooltipAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Juce.ImplementationSelector 4 | { 5 | public class SelectImplementationTooltipAttribute : Attribute 6 | { 7 | public string Tooltip { get; } 8 | 9 | public SelectImplementationTooltipAttribute(string tooltip) 10 | { 11 | Tooltip = tooltip; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationTooltipAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c06edd1690a69f44698ca2162639dfa1 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationTrimDisplayNameAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Juce.ImplementationSelector 4 | { 5 | public class SelectImplementationTrimDisplayNameAttribute : Attribute 6 | { 7 | public string TrimDisplayNameValue { get; } 8 | 9 | public SelectImplementationTrimDisplayNameAttribute(string trimDisplayNameValue) 10 | { 11 | TrimDisplayNameValue = trimDisplayNameValue; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /Runtime/Implementation/SelectImplementationTrimDisplayNameAttribute.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 191df7496fe6d6d48ac546f5efd3ab97 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Runtime/Juce.ImplementationSelector.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Juce.ImplementationSelector.Runtime", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } -------------------------------------------------------------------------------- /Runtime/Juce.ImplementationSelector.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1089a22bce0ea9a468bf8e5a4f8cbad5 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.juce.implementationselector", 3 | "version": "1.0.4", 4 | "displayName": "Juce-ImplementationSelector", 5 | "description": "Editor utility for selecting interface implementations", 6 | "keywords": [ 7 | "Juce", 8 | "Implementation", 9 | "Selector" 10 | ], 11 | "author": { 12 | "name": "Guillem Sunyer", 13 | "email": "juce.unity@gmail.com", 14 | "url": "https://github.com/Juce-Assets/Juce-ImplementationSelector" 15 | }, 16 | "type": "template", 17 | "hideInEditor": false 18 | } 19 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bd0f7aa72d0d97443a07d9c24ed33222 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------