namespace VRTK
|
|
{
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
using UnityEditorInternal;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
[CustomEditor(typeof(VRTK_SDKManager))]
|
|
public class VRTK_SDKManagerEditor : Editor
|
|
{
|
|
private static readonly Dictionary<BuildTargetGroup, bool> isBuildTargetActiveSymbolsFoldOut;
|
|
private ReorderableList setupsList;
|
|
|
|
static VRTK_SDKManagerEditor()
|
|
{
|
|
BuildTargetGroup[] targetGroups = VRTK_SharedMethods.GetValidBuildTargetGroups();
|
|
isBuildTargetActiveSymbolsFoldOut = new Dictionary<BuildTargetGroup, bool>(targetGroups.Length);
|
|
|
|
foreach (BuildTargetGroup targetGroup in targetGroups)
|
|
{
|
|
isBuildTargetActiveSymbolsFoldOut[targetGroup] = true;
|
|
}
|
|
}
|
|
|
|
protected virtual void OnEnable()
|
|
{
|
|
VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
|
|
|
|
setupsList = new ReorderableList(serializedObject, serializedObject.FindProperty("setups"))
|
|
{
|
|
headerHeight = 2,
|
|
drawElementCallback = (rect, index, active, focused) =>
|
|
{
|
|
SerializedProperty serializedProperty = setupsList.serializedProperty;
|
|
if (serializedProperty.arraySize <= index)
|
|
{
|
|
return;
|
|
}
|
|
|
|
rect.y += 2;
|
|
rect.height = EditorGUIUtility.singleLineHeight;
|
|
|
|
Color previousColor = GUI.color;
|
|
if (IsSDKSetupNeverUsed(index))
|
|
{
|
|
GUI.color = new Color(previousColor.r, previousColor.g, previousColor.b, 0.5f);
|
|
}
|
|
|
|
GUIContent unloadButtonGUIContent = new GUIContent("Unload", "Unload this SDK Setup.");
|
|
GUIContent loadButtonGUIContent = new GUIContent("Load", "Try to load this SDK Setup.");
|
|
float buttonGUIContentWidth = Mathf.Max(
|
|
GUI.skin.button.CalcSize(unloadButtonGUIContent).x,
|
|
GUI.skin.button.CalcSize(loadButtonGUIContent).x
|
|
);
|
|
|
|
VRTK_SDKSetup setup = (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue;
|
|
if (EditorApplication.isPlaying && setup != null)
|
|
{
|
|
rect.width -= buttonGUIContentWidth + ReorderableList.Defaults.padding;
|
|
}
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUI.PropertyField(rect,
|
|
serializedProperty.GetArrayElementAtIndex(index),
|
|
GUIContent.none);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
setup = (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue;
|
|
if (setup != null)
|
|
{
|
|
int indexOfExistingDuplicateSetup = Enumerable
|
|
.Range(0, serializedProperty.arraySize)
|
|
.Except(new[] { index })
|
|
.Where(i => (VRTK_SDKSetup)serializedProperty.GetArrayElementAtIndex(i).objectReferenceValue == setup)
|
|
.DefaultIfEmpty(-1)
|
|
.First();
|
|
if (indexOfExistingDuplicateSetup != -1)
|
|
{
|
|
serializedProperty.GetArrayElementAtIndex(indexOfExistingDuplicateSetup).objectReferenceValue = null;
|
|
|
|
setupsList.index = indexOfExistingDuplicateSetup;
|
|
ReorderableList.defaultBehaviours.DoRemoveButton(setupsList);
|
|
setupsList.index = index;
|
|
}
|
|
}
|
|
sdkManager.ManageVRSettings(false);
|
|
}
|
|
|
|
GUI.color = previousColor;
|
|
|
|
if (EditorApplication.isPlaying && setup != null)
|
|
{
|
|
rect.x += rect.width + ReorderableList.Defaults.padding;
|
|
rect.width = buttonGUIContentWidth;
|
|
|
|
if (sdkManager.loadedSetup == setup)
|
|
{
|
|
if (GUI.Button(rect, unloadButtonGUIContent))
|
|
{
|
|
sdkManager.UnloadSDKSetup();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (GUI.Button(rect, loadButtonGUIContent))
|
|
{
|
|
sdkManager.TryLoadSDKSetup(index, true, sdkManager.setups);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
onAddCallback = list =>
|
|
{
|
|
SerializedProperty serializedProperty = list.serializedProperty;
|
|
int index = serializedProperty.arraySize;
|
|
serializedProperty.arraySize++;
|
|
list.index = index;
|
|
|
|
SerializedProperty element = serializedProperty.GetArrayElementAtIndex(index);
|
|
element.objectReferenceValue = null;
|
|
|
|
sdkManager.ManageVRSettings(false);
|
|
},
|
|
onRemoveCallback = list =>
|
|
{
|
|
int index = list.index;
|
|
VRTK_SDKSetup sdkSetup = sdkManager.setups[index];
|
|
bool isLoaded = sdkManager.loadedSetup == sdkSetup;
|
|
|
|
if (isLoaded)
|
|
{
|
|
sdkManager.UnloadSDKSetup();
|
|
}
|
|
|
|
if (sdkSetup != null)
|
|
{
|
|
list.serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue = null;
|
|
}
|
|
|
|
ReorderableList.defaultBehaviours.DoRemoveButton(list);
|
|
sdkManager.ManageVRSettings(false);
|
|
},
|
|
onReorderCallback = list => sdkManager.ManageVRSettings(false)
|
|
};
|
|
|
|
Undo.undoRedoPerformed += UndoRedoPerformed;
|
|
}
|
|
|
|
protected virtual void OnDisable()
|
|
{
|
|
Undo.undoRedoPerformed -= UndoRedoPerformed;
|
|
setupsList = null;
|
|
}
|
|
|
|
public override void OnInspectorGUI()
|
|
{
|
|
serializedObject.Update();
|
|
|
|
VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
|
|
const string manageNowButtonText = "Manage Now";
|
|
|
|
using (new EditorGUILayout.VerticalScope("Box"))
|
|
{
|
|
VRTK_EditorUtilities.AddHeader("Scripting Define Symbols", false);
|
|
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
bool autoManage = EditorGUILayout.Toggle(
|
|
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoManageScriptDefines", "Auto Manage"),
|
|
sdkManager.autoManageScriptDefines,
|
|
GUILayout.ExpandWidth(false)
|
|
);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
serializedObject.FindProperty("autoManageScriptDefines").boolValue = autoManage;
|
|
serializedObject.ApplyModifiedProperties();
|
|
sdkManager.ManageScriptingDefineSymbols(false, true);
|
|
}
|
|
|
|
using (new EditorGUI.DisabledGroupScope(sdkManager.autoManageScriptDefines))
|
|
{
|
|
GUIContent manageNowGUIContent = new GUIContent(
|
|
manageNowButtonText,
|
|
"Manage the scripting define symbols defined by the installed SDKs."
|
|
+ (sdkManager.autoManageScriptDefines
|
|
? "\n\nThis button is disabled because the SDK Manager is set up to manage the scripting define symbols automatically."
|
|
+ " Disable the checkbox on the left to allow managing them manually instead."
|
|
: "")
|
|
);
|
|
if (GUILayout.Button(manageNowGUIContent, GUILayout.MaxHeight(GUI.skin.label.CalcSize(manageNowGUIContent).y)))
|
|
{
|
|
sdkManager.ManageScriptingDefineSymbols(true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
using (new EditorGUILayout.VerticalScope("Box"))
|
|
{
|
|
VRTK_EditorUtilities.AddHeader("Active Symbols Without SDK Classes", false);
|
|
|
|
VRTK_SDKInfo[] availableSDKInfos = VRTK_SDKManager
|
|
.AvailableSystemSDKInfos
|
|
.Concat(VRTK_SDKManager.AvailableBoundariesSDKInfos)
|
|
.Concat(VRTK_SDKManager.AvailableHeadsetSDKInfos)
|
|
.Concat(VRTK_SDKManager.AvailableControllerSDKInfos)
|
|
.ToArray();
|
|
HashSet<string> sdkSymbols = new HashSet<string>(availableSDKInfos.Select(info => info.description.symbol));
|
|
IGrouping<BuildTargetGroup, VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo>[] availableGroupedPredicateInfos = VRTK_SDKManager
|
|
.AvailableScriptingDefineSymbolPredicateInfos
|
|
.GroupBy(info => info.attribute.buildTargetGroup)
|
|
.ToArray();
|
|
foreach (IGrouping<BuildTargetGroup, VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo> grouping in availableGroupedPredicateInfos)
|
|
{
|
|
VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo[] possibleActiveInfos = grouping
|
|
.Where(info => !sdkSymbols.Contains(info.attribute.symbol)
|
|
&& grouping.Except(new[] { info })
|
|
.All(predicateInfo => !(predicateInfo.methodInfo == info.methodInfo
|
|
&& sdkSymbols.Contains(predicateInfo.attribute.symbol))))
|
|
.OrderBy(info => info.attribute.symbol)
|
|
.ToArray();
|
|
if (possibleActiveInfos.Length == 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
EditorGUI.indentLevel++;
|
|
|
|
BuildTargetGroup targetGroup = grouping.Key;
|
|
isBuildTargetActiveSymbolsFoldOut[targetGroup] = EditorGUI.Foldout(
|
|
EditorGUILayout.GetControlRect(),
|
|
isBuildTargetActiveSymbolsFoldOut[targetGroup],
|
|
targetGroup.ToString(),
|
|
true
|
|
);
|
|
|
|
if (isBuildTargetActiveSymbolsFoldOut[targetGroup])
|
|
{
|
|
foreach (VRTK_SDKManager.ScriptingDefineSymbolPredicateInfo predicateInfo in possibleActiveInfos)
|
|
{
|
|
int symbolIndex = sdkManager
|
|
.activeScriptingDefineSymbolsWithoutSDKClasses
|
|
.FindIndex(attribute => attribute.symbol == predicateInfo.attribute.symbol);
|
|
string symbolLabel = predicateInfo.attribute.symbol.Remove(
|
|
0,
|
|
SDK_ScriptingDefineSymbolPredicateAttribute.RemovableSymbolPrefix.Length
|
|
);
|
|
|
|
if (!(bool)predicateInfo.methodInfo.Invoke(null, null))
|
|
{
|
|
symbolLabel += " (not installed)";
|
|
}
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
bool isSymbolActive = EditorGUILayout.ToggleLeft(symbolLabel, symbolIndex != -1);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
Undo.RecordObject(sdkManager, "Active Symbol Change");
|
|
if (isSymbolActive)
|
|
{
|
|
sdkManager.activeScriptingDefineSymbolsWithoutSDKClasses.Add(predicateInfo.attribute);
|
|
}
|
|
else
|
|
{
|
|
sdkManager.activeScriptingDefineSymbolsWithoutSDKClasses.RemoveAt(symbolIndex);
|
|
}
|
|
sdkManager.ManageScriptingDefineSymbols(false, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
}
|
|
|
|
VRTK_EditorUtilities.DrawUsingDestructiveStyle(GUI.skin.button, style =>
|
|
{
|
|
GUIContent clearSymbolsGUIContent = new GUIContent(
|
|
"Remove All Symbols",
|
|
"Remove all scripting define symbols of VRTK. This is handy if you removed the SDK files from your project but still have"
|
|
+ " the symbols defined which results in compile errors."
|
|
+ "\nIf you have the above checkbox enabled the symbols will be managed automatically after clearing them. Otherwise hit the"
|
|
+ " '" + manageNowButtonText + "' button to add the symbols for the currently installed SDKs again."
|
|
);
|
|
|
|
if (GUILayout.Button(clearSymbolsGUIContent, style))
|
|
{
|
|
BuildTargetGroup[] targetGroups = VRTK_SharedMethods.GetValidBuildTargetGroups();
|
|
|
|
foreach (BuildTargetGroup targetGroup in targetGroups)
|
|
{
|
|
string[] currentSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup)
|
|
.Split(';')
|
|
.Distinct()
|
|
.OrderBy(symbol => symbol, StringComparer.Ordinal)
|
|
.ToArray();
|
|
string[] newSymbols = currentSymbols
|
|
.Where(symbol => !symbol.StartsWith(SDK_ScriptingDefineSymbolPredicateAttribute.RemovableSymbolPrefix, StringComparison.Ordinal))
|
|
.ToArray();
|
|
|
|
if (currentSymbols.SequenceEqual(newSymbols))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PlayerSettings.SetScriptingDefineSymbolsForGroup(targetGroup, string.Join(";", newSymbols));
|
|
|
|
string[] removedSymbols = currentSymbols.Except(newSymbols).ToArray();
|
|
if (removedSymbols.Length > 0)
|
|
{
|
|
VRTK_Logger.Info(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SCRIPTING_DEFINE_SYMBOLS_REMOVED, targetGroup, string.Join(", ", removedSymbols)));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
using (new EditorGUILayout.VerticalScope("Box"))
|
|
{
|
|
VRTK_EditorUtilities.AddHeader("Script Aliases", false);
|
|
EditorGUILayout.PropertyField(
|
|
serializedObject.FindProperty("scriptAliasLeftController"),
|
|
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("scriptAliasLeftController", "Left Controller")
|
|
);
|
|
EditorGUILayout.PropertyField(
|
|
serializedObject.FindProperty("scriptAliasRightController"),
|
|
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("scriptAliasRightController", "Right Controller")
|
|
);
|
|
}
|
|
|
|
using (new EditorGUILayout.VerticalScope("Box"))
|
|
{
|
|
VRTK_EditorUtilities.AddHeader("Setups", false);
|
|
|
|
using (new EditorGUILayout.HorizontalScope())
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
bool autoManage = EditorGUILayout.Toggle(
|
|
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoManageVRSettings"),
|
|
sdkManager.autoManageVRSettings,
|
|
GUILayout.ExpandWidth(false)
|
|
);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
serializedObject.FindProperty("autoManageVRSettings").boolValue = autoManage;
|
|
serializedObject.ApplyModifiedProperties();
|
|
sdkManager.ManageVRSettings(false);
|
|
}
|
|
|
|
using (new EditorGUI.DisabledGroupScope(sdkManager.autoManageVRSettings))
|
|
{
|
|
GUIContent manageNowGUIContent = new GUIContent(
|
|
manageNowButtonText,
|
|
"Manage the VR settings of the Player Settings to allow for all the installed SDKs."
|
|
+ (sdkManager.autoManageVRSettings
|
|
? "\n\nThis button is disabled because the SDK Manager is set up to manage the VR Settings automatically."
|
|
+ " Disable the checkbox on the left to allow managing them manually instead."
|
|
: "")
|
|
);
|
|
if (GUILayout.Button(manageNowGUIContent, GUILayout.MaxHeight(GUI.skin.label.CalcSize(manageNowGUIContent).y)))
|
|
{
|
|
sdkManager.ManageVRSettings(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.PropertyField(
|
|
serializedObject.FindProperty("autoLoadSetup"),
|
|
VRTK_EditorUtilities.BuildGUIContent<VRTK_SDKManager>("autoLoadSetup", "Auto Load")
|
|
);
|
|
|
|
setupsList.DoLayoutList();
|
|
|
|
GUIContent autoPopulateGUIContent = new GUIContent("Auto Populate", "Automatically populates the list of SDK Setups with Setups in the scene.");
|
|
if (GUILayout.Button(autoPopulateGUIContent))
|
|
{
|
|
SerializedProperty serializedProperty = setupsList.serializedProperty;
|
|
serializedProperty.ClearArray();
|
|
VRTK_SDKSetup[] setups = sdkManager.GetComponentsInChildren<VRTK_SDKSetup>(true)
|
|
.Concat(VRTK_SharedMethods.FindEvenInactiveComponents<VRTK_SDKSetup>(true))
|
|
.Distinct()
|
|
.ToArray();
|
|
|
|
for (int index = 0; index < setups.Length; index++)
|
|
{
|
|
VRTK_SDKSetup setup = setups[index];
|
|
serializedProperty.InsertArrayElementAtIndex(index);
|
|
serializedProperty.GetArrayElementAtIndex(index).objectReferenceValue = setup;
|
|
}
|
|
}
|
|
|
|
if (sdkManager.setups.Length > 1)
|
|
{
|
|
EditorGUILayout.HelpBox("Duplicated setups are removed automatically.", MessageType.Info);
|
|
}
|
|
|
|
if (Enumerable.Range(0, sdkManager.setups.Length).Any(IsSDKSetupNeverUsed))
|
|
{
|
|
EditorGUILayout.HelpBox("Gray setups will never be loaded because either the SDK Setup isn't valid or there"
|
|
+ " is a valid Setup before it that uses any non-VR SDK.",
|
|
MessageType.Warning);
|
|
}
|
|
}
|
|
|
|
using (new EditorGUILayout.VerticalScope("Box"))
|
|
{
|
|
VRTK_EditorUtilities.AddHeader("Target Platform Group Exclusions", false);
|
|
SerializedProperty excludeTargetGroups = serializedObject.FindProperty("excludeTargetGroups");
|
|
excludeTargetGroups.arraySize = EditorGUILayout.IntField("Size", excludeTargetGroups.arraySize);
|
|
for (int i = 0; i < excludeTargetGroups.arraySize; i++)
|
|
{
|
|
EditorGUILayout.PropertyField(excludeTargetGroups.GetArrayElementAtIndex(i));
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.PropertyField(serializedObject.FindProperty("persistOnLoad"));
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
private void UndoRedoPerformed()
|
|
{
|
|
VRTK_SDKManager sdkManager = (VRTK_SDKManager)target;
|
|
sdkManager.ManageVRSettings(false);
|
|
sdkManager.ManageScriptingDefineSymbols(false, false);
|
|
}
|
|
|
|
private bool IsSDKSetupNeverUsed(int sdkSetupIndex)
|
|
{
|
|
VRTK_SDKSetup[] setups = ((VRTK_SDKManager)target).setups;
|
|
VRTK_SDKSetup setup = setups[sdkSetupIndex];
|
|
|
|
return setup == null
|
|
|| !setup.isValid
|
|
|| Array.FindIndex(
|
|
setups,
|
|
0,
|
|
sdkSetupIndex,
|
|
sdkSetup => sdkSetup != null
|
|
&& sdkSetup.isValid
|
|
&& sdkSetup.usedVRDeviceNames.Contains("None")
|
|
) != -1;
|
|
}
|
|
}
|
|
}
|