Compare commits

...

26 Commits

Author SHA1 Message Date
Makihiro a78f5a340f UIToolKit test 2024-08-03 23:33:05 +09:00
github-actions[bot] 69f6e31cf1 feat: Update package.json to 1.3.1 2024-04-01 07:34:45 +00:00
Makihiro 3ffef8d1b2 Update packages 2024-04-01 16:33:44 +09:00
Makihiro a9763b033d Fix foldout layout on Unity 2022.2 or newer 2024-04-01 16:32:53 +09:00
Makihiro 2b40c3d26e Merge pull request #56 from theo-rapidfire/fix/use-type-cache
Performance improvement: Use TypeCache instead of manual type iteration
2024-04-01 16:02:36 +09:00
theo-rapidfire f7c1017567 Use TypeCache instead of manual type iteration
fix/use-type-cache
2024-03-28 13:39:48 +01:00
Makihiro 301cb4b12c Update README.md 2024-02-18 04:00:28 +09:00
Makihiro fe02e0fd1e Update text editor packages 2024-02-18 03:35:49 +09:00
github-actions[bot] 05efde5001 feat: Update package.json to 1.3.0 2024-02-17 18:07:18 +00:00
Makihiro f275c468ec Merge pull request #55 from mackysoft/feature/reset-reference
Implement new instance context menu
2024-02-18 03:06:43 +09:00
Makihiro c141acf129 Rename to ManagedReferenceContextualPropertyMenu 2024-02-18 03:03:53 +09:00
Makihiro fdc0a286c8 Implement new instance menu 2024-02-18 03:02:41 +09:00
Makihiro e5627b1caf Merge pull request #54 from mackysoft/fix/dropdown-overlap
Fix dropdown overlap in Unity 2023.2
2024-02-18 02:51:05 +09:00
Makihiro 5f54c254f3 Fix foldout layout 2024-02-18 02:43:01 +09:00
Makihiro b8c11e7836 Create SerializedPropertyExtensions and move method 2024-02-18 02:39:33 +09:00
Makihiro f656cd0f12 Add GetChildProperties 2024-02-18 02:38:00 +09:00
Makihiro f69bfc6773 optimize null check 2024-02-18 02:35:23 +09:00
github-actions[bot] 7f424c0f97 feat: Update package.json to 1.2.2 2024-02-16 12:59:32 +00:00
Makihiro 2934eea84e Merge pull request #52 from mackysoft/fix/nullreference-when-fromjson
Fixed a bug when trying to deserialize a null type with FromJson.
2024-02-16 21:58:54 +09:00
Makihiro f781ad7373 Fixed a bug when trying to deserialize a null type with FromJson. 2024-02-16 21:58:38 +09:00
Makihiro e5a5157b3c Merge pull request #48 from JohannesDeml/bugfix/propertydrawer-allow-inheritance
Add logic to check for inherited PropertyDrawers from base classes and interfaces
2024-02-16 20:53:46 +09:00
Makihiro 69830f3583 Merge pull request #49 from JohannesDeml/bugfix/avoid-label-overlap
Fix label overlapping button
2024-02-16 20:50:55 +09:00
Johannes Deml c9b5193e51 Fix use prefixLabel position right away 2024-02-07 19:31:33 +01:00
Johannes Deml a8bcece352 Fix label overlapping button
By drawing the label first we avoid the overlap. By drawing just the label without the foldout we need to work around a unity problem with indentation and apply that ourselves. The foldout property will then be rendered without gui content
2024-01-17 14:40:52 +01:00
Johannes Deml 70f2cdaf16 Add logic to check for inherited PropertyDrawers from base classes and interfaces
This way an inherited drawer will be used if it exists, which might not be too uncommon in the case of SerializeReference fields
2024-01-17 13:27:49 +01:00
Makihiro 97c4e632bc Update README.md 2024-01-10 16:09:00 +09:00
13 changed files with 290 additions and 45 deletions
@@ -1,17 +1,20 @@
// NOTE: managedReferenceValue getter is available only in Unity 2021.3 or later.
#if UNITY_2021_3_OR_NEWER
using System;
using UnityEditor;
using UnityEngine;
namespace MackySoft.SerializeReferenceExtensions.Editor
{
public static class CopyAndPasteProperty
public static class ManagedReferenceContextualPropertyMenu
{
const string kCopiedPropertyPathKey = "SerializeReferenceExtensions.CopiedPropertyPath";
const string kClipboardKey = "SerializeReferenceExtensions.CopyAndPasteProperty";
static readonly GUIContent kPasteContent = new GUIContent("Paste Property");
static readonly GUIContent kNewInstanceContent = new GUIContent("New Instance");
static readonly GUIContent kResetAndNewInstanceContent = new GUIContent("Reset and New Instance");
[InitializeOnLoadMethod]
static void Initialize ()
@@ -38,6 +41,20 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
{
menu.AddDisabledItem(kPasteContent);
}
menu.AddSeparator("");
bool hasInstance = clonedProperty.managedReferenceValue != null;
if (hasInstance)
{
menu.AddItem(kNewInstanceContent, false, NewInstance, clonedProperty);
menu.AddItem(kResetAndNewInstanceContent, false, ResetAndNewInstance, clonedProperty);
}
else
{
menu.AddDisabledItem(kNewInstanceContent);
menu.AddDisabledItem(kResetAndNewInstanceContent);
}
}
}
@@ -62,6 +79,29 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
JsonUtility.FromJsonOverwrite(json, property.managedReferenceValue);
property.serializedObject.ApplyModifiedProperties();
}
static void NewInstance (object customData)
{
SerializedProperty property = (SerializedProperty)customData;
string json = JsonUtility.ToJson(property.managedReferenceValue);
Undo.RecordObject(property.serializedObject.targetObject, "New Instance");
property.managedReferenceValue = JsonUtility.FromJson(json, property.managedReferenceValue.GetType());
property.serializedObject.ApplyModifiedProperties();
Debug.Log($"Create new instance of \"{property.propertyPath}\".");
}
static void ResetAndNewInstance (object customData)
{
SerializedProperty property = (SerializedProperty)customData;
Undo.RecordObject(property.serializedObject.targetObject, "Reset and New Instance");
property.managedReferenceValue = Activator.CreateInstance(property.managedReferenceValue.GetType());
property.serializedObject.ApplyModifiedProperties();
Debug.Log($"Reset property and created new instance of \"{property.propertyPath}\".");
}
}
}
#endif
@@ -4,7 +4,9 @@ using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace MackySoft.SerializeReferenceExtensions.Editor {
namespace MackySoft.SerializeReferenceExtensions.Editor
{
public static class ManagedReferenceUtility {
public static object SetManagedReference (this SerializedProperty property,Type type) {
@@ -12,7 +14,7 @@ namespace MackySoft.SerializeReferenceExtensions.Editor {
#if UNITY_2021_3_OR_NEWER
// NOTE: managedReferenceValue getter is available only in Unity 2021.3 or later.
if (property.managedReferenceValue != null)
if ((type != null) && (property.managedReferenceValue != null))
{
// Restore an previous values from json.
string json = JsonUtility.ToJson(property.managedReferenceValue);
@@ -25,9 +25,10 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
static Type GetCustomPropertyDrawerType (Type type)
{
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (Type drawerType in assembly.GetTypes())
Type[] interfaceTypes = type.GetInterfaces();
var types = TypeCache.GetTypesWithAttribute<CustomPropertyDrawer>();
foreach (Type drawerType in types)
{
var customPropertyDrawerAttributes = drawerType.GetCustomAttributes(typeof(CustomPropertyDrawer), true);
foreach (CustomPropertyDrawer customPropertyDrawer in customPropertyDrawerAttributes)
@@ -36,10 +37,39 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
if (field != null)
{
var fieldType = field.GetValue(customPropertyDrawer) as Type;
if (fieldType != null && fieldType == type)
if (fieldType != null)
{
if (fieldType == type)
{
return drawerType;
}
// If the property drawer also allows for being applied to child classes, check if they match
var useForChildrenField = customPropertyDrawer.GetType().GetField("m_UseForChildren", BindingFlags.NonPublic | BindingFlags.Instance);
if (useForChildrenField != null)
{
object useForChildrenValue = useForChildrenField.GetValue(customPropertyDrawer);
if (useForChildrenValue is bool && (bool)useForChildrenValue)
{
// Check interfaces
if (Array.Exists(interfaceTypes, interfaceType => interfaceType == fieldType))
{
return drawerType;
}
// Check derived types
Type baseType = type.BaseType;
while (baseType != null)
{
if (baseType == fieldType)
{
return drawerType;
}
baseType = baseType.BaseType;
}
}
}
}
}
}
@@ -0,0 +1,31 @@
#if UNITY_2019_3_OR_NEWER
using System.Collections.Generic;
using UnityEditor;
namespace MackySoft.SerializeReferenceExtensions.Editor
{
public static class SerializedPropertyExtensions
{
public static IEnumerable<SerializedProperty> GetChildProperties (this SerializedProperty parent, int depth = 1)
{
parent = parent.Copy();
int depthOfParent = parent.depth;
var enumerator = parent.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current is not SerializedProperty childProperty)
{
continue;
}
if (childProperty.depth > (depthOfParent + depth))
{
continue;
}
yield return childProperty.Copy();
}
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b934aeca38cb7a24cabd6047fe0e298a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
namespace MackySoft.SerializeReferenceExtensions.Editor
{
@@ -31,54 +33,100 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
SerializedProperty m_TargetProperty;
public override void OnGUI (Rect position,SerializedProperty property,GUIContent label) {
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
if (property.propertyType == SerializedPropertyType.ManagedReference) {
// Draw the subclass selector popup.
Rect popupPosition = new Rect(position);
popupPosition.width -= EditorGUIUtility.labelWidth;
popupPosition.x += EditorGUIUtility.labelWidth;
popupPosition.height = EditorGUIUtility.singleLineHeight;
if (property.propertyType == SerializedPropertyType.ManagedReference)
{
// Render label first to avoid label overlap for lists
Rect foldoutLabelRect = new Rect(position);
foldoutLabelRect.height = EditorGUIUtility.singleLineHeight;
foldoutLabelRect = EditorGUI.IndentedRect(foldoutLabelRect);
Rect popupPosition = EditorGUI.PrefixLabel(foldoutLabelRect, label);
if (EditorGUI.DropdownButton(popupPosition,GetTypeName(property),FocusType.Keyboard)) {
// Draw the subclass selector popup.
if (EditorGUI.DropdownButton(popupPosition, GetTypeName(property), FocusType.Keyboard))
{
TypePopupCache popup = GetTypePopup(property);
m_TargetProperty = property;
popup.TypePopup.Show(popupPosition);
}
// Draw the foldout.
if (!string.IsNullOrEmpty(property.managedReferenceFullTypename))
{
Rect foldoutRect = new Rect(position);
foldoutRect.height = EditorGUIUtility.singleLineHeight;
#if UNITY_2022_2_OR_NEWER
// NOTE: Position x must be adjusted.
// FIXME: Is there a more essential solution...?
foldoutRect.x -= 12;
#endif
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, GUIContent.none, true);
}
// Draw property if expanded.
if (property.isExpanded)
{
using (new EditorGUI.IndentLevelScope())
{
// Check if a custom property drawer exists for this type.
PropertyDrawer customDrawer = GetCustomPropertyDrawer(property);
if (customDrawer != null)
{
// Draw the property with custom property drawer.
Rect foldoutRect = new Rect(position);
foldoutRect.height = EditorGUIUtility.singleLineHeight;
property.isExpanded = EditorGUI.Foldout(foldoutRect, property.isExpanded, label, true);
if (property.isExpanded)
{
using (new EditorGUI.IndentLevelScope())
{
Rect indentedRect = position;
float foldoutDifference = EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
indentedRect.height = customDrawer.GetPropertyHeight(property, label);
indentedRect.y += foldoutDifference;
customDrawer.OnGUI(indentedRect, property, label);
}
else
{
// Draw the properties of the child elements.
// NOTE: In the following code, since the foldout layout isn't working properly, I'll iterate through the properties of the child elements myself.
// EditorGUI.PropertyField(position, property, GUIContent.none, true);
Rect childPosition = position;
childPosition.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
foreach (SerializedProperty childProperty in property.GetChildProperties())
{
float height = EditorGUI.GetPropertyHeight(childProperty, new GUIContent(childProperty.displayName, childProperty.tooltip), true);
childPosition.height = height;
EditorGUI.PropertyField(childPosition, childProperty, true);
childPosition.y += height + EditorGUIUtility.standardVerticalSpacing;
}
}
}
}
}
else
{
EditorGUI.PropertyField(position, property, label, true);
}
} else {
EditorGUI.LabelField(position, label, k_IsNotManagedReferenceLabel);
}
EditorGUI.EndProperty();
}
public override VisualElement CreatePropertyGUI (SerializedProperty property)
{
VisualElement root = new VisualElement();
if (property.propertyType == SerializedPropertyType.ManagedReference)
{
TypePopupField typePopupField = new TypePopupField(property, new VisualElement());
root.Add(typePopupField);
}
else
{
return new Label(k_IsNotManagedReferenceLabel.text);
}
return root;
}
PropertyDrawer GetCustomPropertyDrawer (SerializedProperty property)
{
Type propertyType = ManagedReferenceUtility.GetType(property.managedReferenceFullTypename);
@@ -115,7 +163,6 @@ namespace MackySoft.SerializeReferenceExtensions.Editor
foreach (var targetObject in m_TargetProperty.serializedObject.targetObjects) {
SerializedObject individualObject = new SerializedObject(targetObject);
SerializedProperty individualProperty = individualObject.FindProperty(m_TargetProperty.propertyPath);
object obj = individualProperty.SetManagedReference(type);
individualProperty.isExpanded = (obj != null);
@@ -0,0 +1,59 @@
#if UNITY_2019_3_OR_NEWER
using UnityEditor;
using UnityEngine.UIElements;
namespace MackySoft.SerializeReferenceExtensions.Editor
{
public sealed class TypePopupField : BaseField<object>
{
public new static readonly string ussClassName = "unity-base-popup-field";
public static readonly string textUssClassName = ussClassName + "__text";
public static readonly string arrowUssClassName = ussClassName + "__arrow";
public new static readonly string labelUssClassName = ussClassName + "__label";
public new static readonly string inputUssClassName = ussClassName + "__input";
readonly SerializedProperty m_Property;
readonly Toggle m_Toggle;
readonly VisualElement m_ArrowElement;
readonly Label m_TextElement;
public TypePopupField (SerializedProperty property, VisualElement visualInput) : base(property.displayName, visualInput)
{
m_Property = property;
style.flexDirection = FlexDirection.Row;
style.flexShrink = 0;
style.flexGrow = 1;
AddToClassList(ussClassName);
AddToClassList("unity-base-field__aligned");
AddToClassList("unity-base-field__inspector-field");
labelElement.AddToClassList(labelUssClassName);
labelElement.AddToClassList("unity-popup-field__label");
labelElement.AddToClassList("unity-property-field__label");
m_TextElement = new Label(property.displayName)
{
pickingMode = PickingMode.Ignore
};
m_TextElement.AddToClassList(textUssClassName);
visualInput.AddToClassList(inputUssClassName);
visualInput.Add(m_TextElement);
visualInput.pickingMode = PickingMode.Ignore;
m_ArrowElement = new VisualElement();
m_ArrowElement.AddToClassList(arrowUssClassName);
m_ArrowElement.pickingMode = PickingMode.Ignore;
visualInput.Add(m_ArrowElement);
}
}
}
#endif
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad665a39f1251a14ea9f40c0c9cf3a75
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -2,7 +2,7 @@
"name": "com.mackysoft.serializereference-extensions",
"displayName": "SerializeReference Extensions",
"author": { "name": "MackySoft", "url": "https://github.com/mackysoft" },
"version": "1.2.1",
"version": "1.3.1",
"unity": "2021.3",
"description": "Provide popup to specify the type of the field serialized by the [SerializeReference] attribute in the inspector.",
"keywords": [ "SerializeReference", "Editor" ],
+2 -2
View File
@@ -1,7 +1,7 @@
{
"dependencies": {
"com.unity.ide.rider": "3.0.24",
"com.unity.ide.visualstudio": "2.0.18",
"com.unity.ide.rider": "3.0.28",
"com.unity.ide.visualstudio": "2.0.22",
"com.unity.ide.vscode": "1.2.5",
"com.unity.test-framework": "1.1.33",
"com.unity.modules.ai": "1.0.0",
+2 -2
View File
@@ -8,7 +8,7 @@
"url": "https://packages.unity.com"
},
"com.unity.ide.rider": {
"version": "3.0.24",
"version": "3.0.28",
"depth": 0,
"source": "registry",
"dependencies": {
@@ -17,7 +17,7 @@
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": {
"version": "2.0.18",
"version": "2.0.22",
"depth": 0,
"source": "registry",
"dependencies": {
+17 -3
View File
@@ -15,12 +15,19 @@ The `SubclassSelector` attribute allows you to easily set subclasses of those ab
- Easily set subclass by popup.
- **[New]** Type finding by fuzzy finder.
- **[New]** Override the type name and path by the `AddTypeMenu` attribute.
- **[New]** Restore values of previous object from JSON when subclass is changed.
- **[New]** Copy & Paste the subclass properties.
- **[New]** Available `CustomPropertyDrawer` for subclasses.
- **[New]** Restore values of previous object from JSON when subclass is changed. (required Unity 2021.3 or later)
- **[New]** Copy & Paste the subclass properties. (required Unity 2021.3 or later)
- **[New]** Clear & reset the subclass properties. (required Unity 2021.3 or later)
> See below for the reason for the limitation of versions less than Unity 2021.3.
>
> https://blog.unity.com/engine-platform/serializereference-improvements-in-unity-2021-lts
## 📥 Installation
#### Install via `.unitypackage`
Download any version from releases.
Releases: https://github.com/mackysoft/Unity-SerializeReferenceExtensions/releases
@@ -29,10 +36,17 @@ Releases: https://github.com/mackysoft/Unity-SerializeReferenceExtensions/releas
Or, you can add this package by opening PackageManager and entering
`https://github.com/mackysoft/Unity-SerializeReferenceExtensions.git?path=Assets/MackySoft/MackySoft.SerializeReferenceExtensions`
```
https://github.com/mackysoft/Unity-SerializeReferenceExtensions.git?path=Assets/MackySoft/MackySoft.SerializeReferenceExtensions
```
from the `Add package from git URL` option.
If you are specifying a version, enter `#{VERSION}` at the end, as shown below.
```
https://github.com/mackysoft/Unity-SerializeReferenceExtensions.git?path=Assets/MackySoft/MackySoft.SerializeReferenceExtensions#1.1.9
```
#### Install via Open UPM