/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2021. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
using Leap.Unity.Query;
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Leap.Unity.Attributes
{
public class EditorGUIPanelAttribute : CombinablePropertyAttribute,
ITopPanelDrawer
{
public const float LINE_HEIGHT = 20f;
public int heightInLines;
public readonly string editorMethodName;
/// Pass the name of a **static** method in your MonoBehaviour
/// that accepts a Rect and Object[] targets, which reflects the current
/// editor selection (might be multiple of your MonoBehaviours in a
/// multi-select case). The method is called in an OnGUI inspector context,
/// so you can make EditorGUI or GUI calls. See the example below for
/// example usage.
///
/// ```
/// [EditorGUIPanel("DrawPanel")]
/// public SomeType inspectorObj;
/// private static void DrawPanel(Rect panel, Object[] targets) {
/// #if UNITY_EDITOR
/// if (GUI.Button(panel, "Do Thing")) {
/// targets.ForEach≤MyBehaviour≥(r => r.DoThing());
/// }
/// #endif
/// }
/// ```
///
public EditorGUIPanelAttribute(string editorMethodName,
int heightInLines = 1)
{
this.heightInLines = heightInLines;
this.editorMethodName = editorMethodName;
}
#if UNITY_EDITOR
private Action _cachedDelegate;
public float GetHeight()
{
return LINE_HEIGHT * heightInLines;
}
public void Draw(Rect panelRect, SerializedProperty property)
{
if (_cachedDelegate == null)
{
Type type = targets[0].GetType();
MethodInfo method = type.GetMethod(editorMethodName,
BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Static |
BindingFlags.Instance |
BindingFlags.FlattenHierarchy
);
if (method == null)
{
Debug.LogWarning("Could not find method of the name " +
editorMethodName + " " + "to invoke for the TopButtonPanel " +
"attribute.");
return;
}
int paramCount = method.GetParameters().Length;
if (paramCount == 0)
{
Debug.LogWarning("Method " + editorMethodName + "needs to accept a " +
"Rect arg and Object[] arg to know the size of the panel to draw and " +
"which components are currently selected.");
}
// else if (paramCount == 1) {
// Debug.LogWarning("Method " + editorMethodName + "needs to accept a " +
// "Rect arg and Object[] arg to know the size of the panel to draw and " +
// "which components are currently selected.");
// }
else if (paramCount == 1 || paramCount == 2)
{
_cachedDelegate = (rect, targets) =>
{
if (!method.IsStatic)
{
// Non-static drawing is only valid for single-object selection.
if (targets.Length == 1)
{
object[] argArray = new object[1];
argArray[0] = rect;
method.Invoke(targets[0], argArray);
}
}
else
{ // method.IsStatic
object[] argArray = new object[2];
argArray[0] = rect;
argArray[1] = targets;
method.Invoke(null, argArray);
}
};
}
else
{
Debug.LogWarning("Could not invoke the method " + editorMethodName +
" from TopButtonPanel because the method had more than 1 argument.");
}
}
_cachedDelegate.Invoke(panelRect, targets);
return;
}
#endif
}
}