Last active
May 31, 2022 06:04
-
-
Save Baste-RainGames/2aed9b5ce2b1b414fd65aa72c66d7f3b to your computer and use it in GitHub Desktop.
Interaction with Unity's DragAndDropService
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Reflection; | |
using UnityEditor; | |
using UnityEditorInternal; | |
using UnityEngine; | |
// This class gives access to Unity's internal DragAndDropService class through reflection, and exposes the same methods. | |
// See https://github.com/Unity-Technologies/UnityCsReference/blob/f50ab75c509cab05254e0ff2f06eb74f5ecd30da/Editor/Mono/DragAndDropService.cs | |
namespace RainDragAndDropService { | |
public static class DragAndDropService { | |
public static int kProjectBrowserDropDstId = "ProjectBrowser".GetHashCode(); | |
public static int kSceneDropDstId = "SceneView".GetHashCode(); | |
public static int kHierarchyDropDstId = "Hierarchy".GetHashCode(); | |
public static int kInspectorDropDstId = "Inspector".GetHashCode(); | |
public delegate DragAndDropVisualMode ProjectBrowserDropHandler(int dragInstanceId, string dropUponPath, bool perform); | |
public delegate DragAndDropVisualMode SceneDropHandler(UnityEngine.Object dropUpon, Vector3 worldPosition, Vector2 viewportPosition, | |
Transform parentForDraggedObjects, bool perform); | |
public delegate DragAndDropVisualMode HierarchyDropHandler(int dropTargetInstanceID, InternalEditorUtility.HierarchyDropMode dropMode, | |
Transform parentForDraggedObjects, bool perform); | |
public delegate DragAndDropVisualMode InspectorDropHandler(UnityEngine.Object[] targets, bool perform); | |
public static Action AddDropHandler(ProjectBrowserDropHandler handler) { | |
return AddDropHandler(kProjectBrowserDropDstId, handler); | |
} | |
public static Action AddDropHandler(SceneDropHandler handler) { | |
return AddDropHandler(kSceneDropDstId, handler); | |
} | |
public static Action AddDropHandler(HierarchyDropHandler handler) { | |
return AddDropHandler(kHierarchyDropDstId, handler); | |
} | |
public static Action AddDropHandler(InspectorDropHandler handler) { | |
return AddDropHandler(kInspectorDropDstId, handler); | |
} | |
public static Action AddDropHandler(int dropDstId, Delegate handler) { | |
twoArgsArray[0] = dropDstId; | |
twoArgsArray[1] = handler; | |
return (Action) AddDropHandlerMethod.Invoke(null, twoArgsArray); | |
} | |
public static bool HasHandler(int dropDstId, Delegate handler) { | |
twoArgsArray[0] = dropDstId; | |
twoArgsArray[1] = handler; | |
return (bool) HasHandlerMethod.Invoke(null, twoArgsArray); | |
} | |
public static void RemoveDropHandler(int dropDstId, Delegate handler) { | |
twoArgsArray[0] = dropDstId; | |
twoArgsArray[1] = handler; | |
RemoveDropHandlerMethod.Invoke(null, twoArgsArray); | |
} | |
public static DragAndDropVisualMode Drop(int dropDstId, params object[] args) { | |
twoArgsArray[0] = dropDstId; | |
twoArgsArray[1] = args; | |
return (DragAndDropVisualMode) DropMethod.Invoke(null, twoArgsArray); | |
} | |
#region Reflection | |
private static object[] twoArgsArray = new object[2]; | |
private static Type _dragAndDropServiceType; | |
private static Type DragAndDropServiceType { | |
get { | |
if (_dragAndDropServiceType == null) | |
_dragAndDropServiceType = Assembly.GetAssembly(typeof(Editor)).GetType("UnityEditor.DragAndDropService"); | |
return _dragAndDropServiceType; | |
} | |
} | |
private static MethodInfo _addDropHandlerMethod; | |
private static MethodInfo AddDropHandlerMethod { | |
get { | |
if (_addDropHandlerMethod == null) | |
_addDropHandlerMethod = DragAndDropServiceType.GetMethod("AddDropHandler", BindingFlags.Public | BindingFlags.Static, null, | |
new[] {typeof(int), typeof(Delegate)}, null); | |
return _addDropHandlerMethod; | |
} | |
} | |
private static MethodInfo _hasHandlerMethod; | |
private static MethodInfo HasHandlerMethod { | |
get { | |
if (_hasHandlerMethod == null) | |
_hasHandlerMethod = DragAndDropServiceType.GetMethod("HasHandler"); | |
return _hasHandlerMethod; | |
} | |
} | |
private static MethodInfo _removeDropHandlerMethod; | |
private static MethodInfo RemoveDropHandlerMethod { | |
get { | |
if (_removeDropHandlerMethod == null) | |
_removeDropHandlerMethod = DragAndDropServiceType.GetMethod("RemoveDropHandler"); | |
return _removeDropHandlerMethod; | |
} | |
} | |
private static MethodInfo _dropMethod; | |
private static MethodInfo DropMethod { | |
get { | |
if (_dropMethod == null) | |
_dropMethod = DragAndDropServiceType.GetMethod("Drop"); | |
return _dropMethod; | |
} | |
} | |
#endregion | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Example use case: make dragging sprites onto GameObjects add them as SpriteRenderers: | |
using System.Collections.Generic; | |
using RainDragAndDropService; | |
using UnityEditor; | |
using UnityEngine; | |
public static class SpriteDragAndDrop { | |
[InitializeOnLoadMethod] | |
public static void HookUpDragAndDropToInspector() { | |
var dropHandler = (DragAndDropService.InspectorDropHandler) OnInspectorDrop; | |
if (!DragAndDropService.HasHandler(DragAndDropService.kHierarchyDropDstId, dropHandler)) | |
DragAndDropService.AddDropHandler(dropHandler); | |
} | |
private static List<GameObject> targetGameObjects = new List<GameObject>(); | |
private static DragAndDropVisualMode OnInspectorDrop(Object[] targets, bool perform) { | |
targetGameObjects.Clear(); | |
foreach (var target in targets) | |
if (target is GameObject gameObject && gameObject.GetComponent<SpriteRenderer>() == null) | |
targetGameObjects.Add(gameObject); | |
if (targetGameObjects.Count == 0) | |
return DragAndDropVisualMode.None; // this allows other drag and drop handlers to handle the drag | |
Sprite sprite = null; | |
foreach (var obj in DragAndDrop.objectReferences) | |
if (obj is Sprite s) { | |
sprite = s; | |
break; | |
} | |
if (sprite == null) { | |
foreach (var obj in DragAndDrop.objectReferences) | |
if (obj is Texture t) { | |
sprite = AssetDatabase.LoadAssetAtPath<Sprite>(AssetDatabase.GetAssetPath(t)); | |
if (sprite != null) | |
break; | |
} | |
} | |
if (sprite == null) | |
return DragAndDropVisualMode.None; | |
if (perform) { | |
foreach (var gameObject in targetGameObjects) | |
Undo.AddComponent<SpriteRenderer>(gameObject).sprite = sprite; | |
} | |
return DragAndDropVisualMode.Link; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment