Skip to content

Commit

Permalink
Update project to Unity 2021.x; implement SerializeReference-based co…
Browse files Browse the repository at this point in the history
…ntext menu operations (Copy, Paster, Duplicate)
  • Loading branch information
arimger committed Aug 26, 2024
1 parent 298c0cf commit 184c24d
Show file tree
Hide file tree
Showing 26 changed files with 750 additions and 120 deletions.
8 changes: 8 additions & 0 deletions Assets/Editor Toolbox/Editor/ContextMenu.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions Assets/Editor Toolbox/Editor/ContextMenu/IContextMenuOperation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using UnityEditor;
using UnityEngine;

namespace Toolbox.Editor.ContextMenu
{
internal interface IContextMenuOperation
{
bool IsVisible(SerializedProperty property);
bool IsEnabled(SerializedProperty property);
void Perform(SerializedProperty property);

GUIContent Label { get; }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Assets/Editor Toolbox/Editor/ContextMenu/Management.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Collections.Generic;

using UnityEditor;

namespace Toolbox.Editor.ContextMenu.Management
{
using Toolbox.Editor.ContextMenu.Operations;

[InitializeOnLoad]
internal static class ToolboxContextMenuManager
{
private static readonly List<IContextMenuOperation> registeredOperations;

static ToolboxContextMenuManager()
{
registeredOperations = new List<IContextMenuOperation>()
{
new CopySerializeReferenceOperation(),
new PasteSerializeReferenceOperation(),
new DuplicateSerializeReferenceArrayElementOperation()
};

EditorApplication.contextualPropertyMenu -= OnContextMenuOpening;
EditorApplication.contextualPropertyMenu += OnContextMenuOpening;
}

public static void AppendOpertation(IContextMenuOperation operation)
{
registeredOperations.Add(operation);
}

public static bool RemoveOperation(IContextMenuOperation operation)
{
return registeredOperations.Remove(operation);
}

private static void OnContextMenuOpening(GenericMenu menu, SerializedProperty property)
{
foreach (var operation in registeredOperations)
{
if (!operation.IsVisible(property))
{
continue;
}

var label = operation.Label;
if (!operation.IsEnabled(property))
{
menu.AddDisabledItem(label);
continue;
}

menu.AddItem(label, false, () =>
{
operation.Perform(property);
});
}
}
}
}
8 changes: 8 additions & 0 deletions Assets/Editor Toolbox/Editor/ContextMenu/Operations.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using UnityEditor;
using UnityEngine;

namespace Toolbox.Editor.ContextMenu.Operations
{
internal class CopySerializeReferenceOperation : IContextMenuOperation
{
internal static CopySerializedRererenceCache Cache { get; private set; }

public bool IsVisible(SerializedProperty property)
{
#if UNITY_2021_3_OR_NEWER
return property != null && property.propertyType == SerializedPropertyType.ManagedReference;
#else
return false;
#endif
}

public bool IsEnabled(SerializedProperty property)
{
return true;
}

public void Perform(SerializedProperty property)
{
#if UNITY_2021_3_OR_NEWER
var value = property.managedReferenceValue;
if (value != null)
{
var referenceType = value.GetType();
var data = JsonUtility.ToJson(value);
Cache = new CopySerializedRererenceCache(referenceType, data);
return;
}

Cache = new CopySerializedRererenceCache(null, null);
#endif
}

public GUIContent Label => new GUIContent("Copy Serialize Reference");

[InitializeOnLoadMethod]
private static void Initialize()
{
Cache = null;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace Toolbox.Editor.ContextMenu.Operations
{
internal class CopySerializedRererenceCache
{
public CopySerializedRererenceCache(Type referenceType, string data)
{
ReferenceType = referenceType;
Data = data;
}

public Type ReferenceType { get; }
public string Data { get; }
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using UnityEditor;
using UnityEngine;

namespace Toolbox.Editor.ContextMenu.Operations
{
internal class DuplicateSerializeReferenceArrayElementOperation : IContextMenuOperation
{
public GUIContent Label => new GUIContent("Duplicate Serialize Reference Array Element");

public bool IsVisible(SerializedProperty property)
{
#if UNITY_2021_3_OR_NEWER
return property != null && property.propertyType == SerializedPropertyType.ManagedReference &&
PropertyUtility.IsSerializableArrayElement(property);
#else
return false;
#endif
}

public bool IsEnabled(SerializedProperty property)
{
return true;
}

public void Perform(SerializedProperty property)
{
var sourceProperty = property.Copy();
sourceProperty.serializedObject.Update();
var sourceValue = sourceProperty.managedReferenceValue;

var arrayProperty = PropertyUtility.GetArray(sourceProperty);
var newElementIndex = arrayProperty.arraySize;
arrayProperty.arraySize = newElementIndex + 1;
//NOTE: there will be null by default anyway
if (sourceValue != null)
{
var targetData = JsonUtility.ToJson(sourceValue);
var targetValue = JsonUtility.FromJson(targetData, sourceValue.GetType());
var targetProperty = arrayProperty.GetArrayElementAtIndex(newElementIndex);
targetProperty.managedReferenceValue = targetValue;
}

sourceProperty.serializedObject.ApplyModifiedProperties();
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;

using UnityEditor;
using UnityEngine;

namespace Toolbox.Editor.ContextMenu.Operations
{

internal class PasteSerializeReferenceOperation : IContextMenuOperation
{
private object GetCachedManagedReferenceValue()
{
var cachedData = CopySerializeReferenceOperation.Cache;
if (cachedData.ReferenceType != null)
{
var newValue = JsonUtility.FromJson(cachedData.Data, cachedData.ReferenceType);
return newValue;
}
else
{
return null;
}
}

public bool IsVisible(SerializedProperty property)
{
#if UNITY_2021_3_OR_NEWER
return property != null && property.propertyType == SerializedPropertyType.ManagedReference;
#else
return false;
#endif
}

public bool IsEnabled(SerializedProperty property)
{
return CopySerializeReferenceOperation.Cache != null;
}

public void Perform(SerializedProperty property)
{
var targetProperty = property.Copy();
try
{
targetProperty.serializedObject.Update();
targetProperty.managedReferenceValue = GetCachedManagedReferenceValue();
targetProperty.serializedObject.ApplyModifiedProperties();
}
catch (Exception)
{ }
}

public GUIContent Label => new GUIContent("Paste Serialize Reference");
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 184c24d

Please sign in to comment.