Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
/******************************************************************************
* Copyright (C) Leap Motion, Inc. 2011-2018. *
* Leap Motion proprietary and confidential. *
* *
* Use subject to the terms of the Leap Motion SDK Agreement available at *
* https://developer.leapmotion.com/sdk_agreement, or another agreement *
* between Leap Motion and you, your company or other organization. *
******************************************************************************/
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEditor;
using UnityEditorInternal;
using Leap.Unity;
using Leap.Unity.Query;
namespace Leap.Unity.GraphicalRenderer {
public class LeapGuiGroupEditor {
public const int BUTTON_WIDTH = 30;
public const int REFRESH_WIDTH = 78;
private LeapGraphicRenderer _renderer;
private SerializedObject _serializedObject;
private SerializedProperty _supportInfo;
private SerializedProperty _groupProperty;
private SerializedProperty _multiFeatureList;
private SerializedProperty _multiRenderingMethod;
private SerializedProperty _featureTable;
private ReorderableList _featureList;
private MonoScript _renderingMethodMonoScript;
private List<SerializedProperty> _cachedPropertyList;
private List<float> _cachedPropertyHeights;
private SerializedProperty _renderingMethod;
private GenericMenu _addRenderingMethodMenu;
private GenericMenu _addFeatureMenu;
public LeapGuiGroupEditor(LeapGraphicRenderer renderer, SerializedObject serializedObject) {
_renderer = renderer;
_serializedObject = serializedObject;
var allTypes = Assembly.GetAssembly(typeof(LeapGraphicRenderer)).GetTypes();
var allRenderingMethods = allTypes.Query().
Where(t => !t.IsAbstract &&
!t.IsGenericType &&
t.IsSubclassOf(typeof(LeapRenderingMethod)));
_addRenderingMethodMenu = new GenericMenu();
foreach (var renderingMethod in allRenderingMethods) {
_addRenderingMethodMenu.AddItem(new GUIContent(LeapGraphicTagAttribute.GetTagName(renderingMethod)),
false,
() => {
serializedObject.ApplyModifiedProperties();
Undo.RecordObject(_renderer, "Changed rendering method");
EditorUtility.SetDirty(_renderer);
_renderer.editor.ChangeRenderingMethodOfSelectedGroup(renderingMethod, addFeatures: false);
serializedObject.Update();
_renderer.editor.ScheduleRebuild();
_serializedObject.SetIsDifferentCacheDirty();
});
}
var allFeatures = allTypes.Query().
Where(t => !t.IsAbstract &&
!t.IsGenericType &&
t.IsSubclassOf(typeof(LeapGraphicFeatureBase))).ToList();
allFeatures.Sort((a, b) => {
var tagA = LeapGraphicTagAttribute.GetTag(a);
var tagB = LeapGraphicTagAttribute.GetTag(b);
var orderA = tagA == null ? 0 : tagA.order;
var orderB = tagB == null ? 0 : tagB.order;
return orderA - orderB;
});
_addFeatureMenu = new GenericMenu();
foreach (var item in allFeatures.Query().WithPrevious(includeStart: true)) {
var tag = LeapGraphicTagAttribute.GetTag(item.value);
var order = tag == null ? 0 : tag.order;
if (item.hasPrev) {
var prevTag = LeapGraphicTagAttribute.GetTag(item.prev);
var prevOrder = prevTag == null ? 0 : prevTag.order;
if ((prevOrder / 100) != (order / 100)) {
_addFeatureMenu.AddSeparator("");
}
}
_addFeatureMenu.AddItem(new GUIContent(tag.name),
false,
() => {
if (item.value.ImplementsInterface(typeof(ICustomChannelFeature)) && LeapGraphicPreferences.promptWhenAddCustomChannel) {
int result = EditorUtility.DisplayDialogComplex("Adding Custom Channel", "Custom channels can only be utilized by writing custom shaders, are you sure you want to continue?", "Add it", "Cancel", "Add it from now on");
switch (result) {
case 0:
break;
case 1:
return;
case 2:
LeapGraphicPreferences.promptWhenAddCustomChannel = false;
break;
}
}
serializedObject.ApplyModifiedProperties();
Undo.RecordObject(_renderer, "Added feature");
EditorUtility.SetDirty(_renderer);
_renderer.editor.AddFeatureToSelectedGroup(item.value);
_serializedObject.Update();
_serializedObject.SetIsDifferentCacheDirty();
});
}
}
public void Invalidate() {
_featureList = null;
_renderingMethodMonoScript = null;
}
public void DoGuiLayout(SerializedProperty groupProperty) {
using (new ProfilerSample("Draw Graphic Group")) {
init(groupProperty);
drawRendererHeader();
drawGroupName();
drawMonoScript();
drawStatsArea();
drawSpriteWarning();
EditorGUILayout.PropertyField(_renderingMethod, includeChildren: true);
EditorGUILayout.Space();
drawFeatureHeader();
_featureList.DoLayoutList();
drawWarningDialogs();
}
}
private void init(SerializedProperty groupProperty) {
Assert.IsNotNull(groupProperty);
_groupProperty = groupProperty;
_multiFeatureList = _groupProperty.FindPropertyRelative("_features");
_multiRenderingMethod = _groupProperty.FindPropertyRelative("_renderingMethod");
_featureTable = MultiTypedListUtil.GetTableProperty(_multiFeatureList);
Assert.IsNotNull(_featureTable);
if (_featureList == null || !SerializedProperty.EqualContents(_featureList.serializedProperty, _featureTable)) {
_featureList = new ReorderableList(_serializedObject,
_featureTable,
draggable: true,
displayHeader: false,
displayAddButton: false,
displayRemoveButton: false);
_featureList.showDefaultBackground = false;
_featureList.headerHeight = 0;
_featureList.elementHeight = EditorGUIUtility.singleLineHeight;
_featureList.elementHeightCallback = featureHeightCallback;
_featureList.drawElementCallback = drawFeatureCallback;
_featureList.onReorderCallback = onReorderFeaturesCallback;
}
_renderingMethod = MultiTypedReferenceUtil.GetReferenceProperty(_multiRenderingMethod);
_supportInfo = _groupProperty.FindPropertyRelative("_supportInfo");
_cachedPropertyList = new List<SerializedProperty>();
_cachedPropertyHeights = new List<float>();
for (int i = 0; i < _featureTable.arraySize; i++) {
var idIndex = _featureTable.GetArrayElementAtIndex(i);
var referenceProp = MultiTypedListUtil.GetReferenceProperty(_multiFeatureList, idIndex);
_cachedPropertyList.Add(referenceProp);
//Make sure to add one line for the label
_cachedPropertyHeights.Add(EditorGUI.GetPropertyHeight(referenceProp) + EditorGUIUtility.singleLineHeight);
}
_renderingMethod = MultiTypedReferenceUtil.GetReferenceProperty(_multiRenderingMethod);
if (_renderingMethodMonoScript == null) {
_renderingMethodMonoScript = AssetDatabase.FindAssets(_renderingMethod.type).
Query().
Where(guid => !string.IsNullOrEmpty(guid)).
Select(guid => AssetDatabase.GUIDToAssetPath(guid)).
Where(path => Path.GetFileNameWithoutExtension(path) == _renderingMethod.type).
Select(path => AssetDatabase.LoadAssetAtPath<MonoScript>(path)).
FirstOrDefault();
}
}
private void drawGroupName() {
var nameProperty = _groupProperty.FindPropertyRelative("_groupName");
EditorGUILayout.PropertyField(nameProperty);
nameProperty.stringValue = nameProperty.stringValue.Trim();
if (string.IsNullOrEmpty(nameProperty.stringValue)) {
nameProperty.stringValue = "MyGroupName";
}
}
private void drawRendererHeader() {
Rect rect = EditorGUILayout.GetControlRect(GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight));
Rect left, right;
rect.SplitHorizontallyWithRight(out left, out right, BUTTON_WIDTH * 2);
if (!EditorApplication.isPlaying && PrefabUtility.GetPrefabType(_renderer) != PrefabType.Prefab) {
var mesher = _renderer.editor.GetSelectedRenderingMethod() as LeapMesherBase;
if (mesher != null) {
Color prevColor = GUI.color;
if (mesher.IsAtlasDirty) {
GUI.color = Color.yellow;
}
Rect middle;
left.SplitHorizontallyWithRight(out left, out middle, REFRESH_WIDTH);
if (GUI.Button(middle, "Refresh Atlas", EditorStyles.miniButtonMid)) {
_serializedObject.ApplyModifiedProperties();
Undo.RecordObject(_renderer, "Refreshed atlas");
EditorUtility.SetDirty(_renderer);
mesher.RebuildAtlas(new ProgressBar());
_renderer.editor.ScheduleRebuild();
_serializedObject.Update();
}
GUI.color = prevColor;
}
}
EditorGUI.LabelField(left, "Renderer", EditorStyles.miniButtonLeft);
using (new EditorGUI.DisabledGroupScope(EditorApplication.isPlaying)) {
if (GUI.Button(right, "v", EditorStyles.miniButtonRight)) {
_addRenderingMethodMenu.ShowAsContext();
}
}
}
private void drawStatsArea() {
using (new EditorGUI.DisabledGroupScope(true)) {
var graphicList = _groupProperty.FindPropertyRelative("_graphics");
int count = graphicList.arraySize;
EditorGUILayout.IntField("Attached Graphic Count", count);
}
}
private void drawSpriteWarning() {
var list = Pool<List<LeapGraphicFeatureBase>>.Spawn();
try {
foreach (var group in _renderer.groups) {
list.AddRange(group.features);
}
SpriteAtlasUtil.ShowInvalidSpriteWarning(list);
} finally {
list.Clear();
Pool<List<LeapGraphicFeatureBase>>.Recycle(list);
}
}
private void drawMonoScript() {
using (new EditorGUI.DisabledGroupScope(true)) {
EditorGUILayout.ObjectField("Rendering Method",
_renderingMethodMonoScript,
typeof(MonoScript),
allowSceneObjects: false);
}
}
private void drawWarningDialogs() {
HashSet<string> shownMessages = Pool<HashSet<string>>.Spawn();
try {
for (int i = 0; i < _cachedPropertyList.Count; i++) {
if (!EditorApplication.isPlaying) {
var supportInfo = _supportInfo.GetArrayElementAtIndex(i);
var supportProperty = supportInfo.FindPropertyRelative("support");
var messageProperty = supportInfo.FindPropertyRelative("message");
if (shownMessages.Contains(messageProperty.stringValue)) {
continue;
}
shownMessages.Add(messageProperty.stringValue);
switch ((SupportType)supportProperty.intValue) {
case SupportType.Warning:
EditorGUILayout.HelpBox(messageProperty.stringValue, MessageType.Warning);
break;
case SupportType.Error:
EditorGUILayout.HelpBox(messageProperty.stringValue, MessageType.Error);
break;
}
}
}
} finally {
shownMessages.Clear();
Pool<HashSet<string>>.Recycle(shownMessages);
}
}
private void drawFeatureHeader() {
Rect rect = EditorGUILayout.GetControlRect(GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight));
Rect left, middle, right;
rect.SplitHorizontallyWithRight(out middle, out right, BUTTON_WIDTH);
middle.SplitHorizontallyWithRight(out left, out middle, BUTTON_WIDTH);
EditorGUI.LabelField(left, "Graphic Features", EditorStyles.miniButtonLeft);
using (new EditorGUI.DisabledGroupScope(EditorApplication.isPlaying)) {
EditorGUI.BeginDisabledGroup(_featureTable.arraySize == 0);
if (GUI.Button(middle, "-", EditorStyles.miniButtonMid) && _featureList.index >= 0) {
_serializedObject.ApplyModifiedProperties();
Undo.RecordObject(_renderer, "Removed Feature");
EditorUtility.SetDirty(_renderer);
_renderer.editor.RemoveFeatureFromSelectedGroup(_featureList.index);
_serializedObject.Update();
init(_groupProperty);
}
EditorGUI.EndDisabledGroup();
if (GUI.Button(right, "+", EditorStyles.miniButtonRight)) {
_addFeatureMenu.ShowAsContext();
}
}
}
// Feature list callbacks
private void drawFeatureHeaderCallback(Rect rect) {
Rect left, right;
rect.SplitHorizontallyWithRight(out left, out right, BUTTON_WIDTH);
EditorGUI.LabelField(left, "Graphic Features", EditorStyles.miniButtonLeft);
if (GUI.Button(right, "+", EditorStyles.miniButtonRight)) {
_addFeatureMenu.ShowAsContext();
}
}
private float featureHeightCallback(int index) {
return _cachedPropertyHeights[index];
}
delegate void Action<T1, T2, T3, T4, T5>(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5);
private void drawFeatureCallback(Rect rect, int index, bool isActive, bool isFocused) {
var featureProperty = _cachedPropertyList[index];
rect = rect.SingleLine();
string featureName = LeapGraphicTagAttribute.GetTagName(featureProperty.type);
int lastIndexOf = featureName.LastIndexOf('/');
if (lastIndexOf >= 0) {
featureName = featureName.Substring(lastIndexOf + 1);
}
GUIContent featureLabel = new GUIContent(featureName);
Color originalColor = GUI.color;
if (!EditorApplication.isPlaying &&
index < _supportInfo.arraySize) {
var supportInfo = _supportInfo.GetArrayElementAtIndex(index);
var supportProperty = supportInfo.FindPropertyRelative("support");
var messageProperty = supportInfo.FindPropertyRelative("message");
switch ((SupportType)supportProperty.intValue) {
case SupportType.Warning:
GUI.color = Color.yellow;
featureLabel.tooltip = messageProperty.stringValue;
break;
case SupportType.Error:
GUI.color = Color.red;
featureLabel.tooltip = messageProperty.stringValue;
break;
}
}
Vector2 size = EditorStyles.label.CalcSize(featureLabel);
Rect labelRect = rect;
labelRect.width = size.x;
GUI.Box(labelRect, "");
EditorGUI.LabelField(labelRect, featureLabel);
GUI.color = originalColor;
rect = rect.NextLine().Indent();
EditorGUI.PropertyField(rect, featureProperty, includeChildren: true);
}
private void onReorderFeaturesCallback(ReorderableList list) {
_renderer.editor.ScheduleRebuild();
}
}
}
2046045a2This file is pinned to the selected release. Download the original to open it in your design tool.