741 lines
32 KiB
C#
741 lines
32 KiB
C#
|
using UnityEngine;
|
|||
|
using System.Collections;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEditor;
|
|||
|
using UnityEditor.UI;
|
|||
|
using UnityEngine.EventSystems;
|
|||
|
#if CURVEDUI_TMP || TMP_PRESENT
|
|||
|
using TMPro;
|
|||
|
#endif
|
|||
|
|
|||
|
#if CURVEDUI_STEAMVR_2
|
|||
|
using Valve.VR;
|
|||
|
using System.Reflection;
|
|||
|
using System;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
namespace CurvedUI {
|
|||
|
|
|||
|
|
|||
|
[CustomEditor(typeof(CurvedUISettings))]
|
|||
|
[ExecuteInEditMode]
|
|||
|
public class CurvedUISettingsEditor : Editor {
|
|||
|
|
|||
|
#pragma warning disable 414
|
|||
|
bool ShowRemoveCurvedUI = false;
|
|||
|
static bool ShowAdvaced = false;
|
|||
|
bool loadingCustomDefine = false;
|
|||
|
static bool CUIeventSystemPresent = false;
|
|||
|
private bool inPrefabMode = false;
|
|||
|
|
|||
|
[SerializeField][HideInInspector]
|
|||
|
Dictionary<CurvedUIInputModule.CUIControlMethod, string> m_controlMethodDefineDict;
|
|||
|
|
|||
|
#if CURVEDUI_STEAMVR_2
|
|||
|
SteamVR_Action_Boolean[] steamVRActions;
|
|||
|
string[] steamVRActionsPaths;
|
|||
|
#endif
|
|||
|
|
|||
|
#pragma warning restore 414
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#region LIFECYCLE
|
|||
|
void Awake()
|
|||
|
{
|
|||
|
AddCurvedUIComponents();
|
|||
|
}
|
|||
|
|
|||
|
void OnEnable()
|
|||
|
{
|
|||
|
//if we're firing OnEnable, this means any compilation has ended. We're good!
|
|||
|
loadingCustomDefine = false;
|
|||
|
|
|||
|
//look for CurvedUI custom EventSystem -> we'll check later if it makes sense to have one.
|
|||
|
CUIeventSystemPresent = (FindObjectsOfType(typeof(CurvedUIEventSystem)).Length > 0);
|
|||
|
|
|||
|
//hacky way to make sure event is connected only once, but it works!
|
|||
|
#if UNITY_2018_1_OR_NEWER
|
|||
|
EditorApplication.hierarchyChanged -= AddCurvedUIComponents;
|
|||
|
EditorApplication.hierarchyChanged -= AddCurvedUIComponents;
|
|||
|
EditorApplication.hierarchyChanged += AddCurvedUIComponents;
|
|||
|
#else
|
|||
|
//hacky way to make sure event is connected only once, but it works!
|
|||
|
EditorApplication.hierarchyWindowChanged -= AddCurvedUIComponents;
|
|||
|
EditorApplication.hierarchyWindowChanged -= AddCurvedUIComponents;
|
|||
|
EditorApplication.hierarchyWindowChanged += AddCurvedUIComponents;
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//Warnings-------------------------------------//
|
|||
|
if (Application.isPlaying)
|
|||
|
{
|
|||
|
CurvedUISettings myTarget = (CurvedUISettings)target;
|
|||
|
|
|||
|
//Canvas' layer not included in RaycastLayerMask warning
|
|||
|
if (!IsInLayerMask(myTarget.gameObject.layer, CurvedUIInputModule.Instance.RaycastLayerMask) &&
|
|||
|
myTarget.Interactable)
|
|||
|
{
|
|||
|
Debug.LogError("CURVEDUI: " + WarningLayerNotIncluded, myTarget.gameObject);
|
|||
|
}
|
|||
|
|
|||
|
//check if the currently selected control method is enabled in editor.
|
|||
|
//Otherwise, show error.
|
|||
|
string define = PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
|
|||
|
foreach(var key in ControlMethodDefineDict.Keys)
|
|||
|
{
|
|||
|
if(myTarget.ControlMethod == key && !define.Contains(ControlMethodDefineDict[key]))
|
|||
|
Debug.LogError("CURVEDUI: Selected control method (" + key.ToString() + ") is not enabled. " +
|
|||
|
"Enable it on CurvedUISettings component", myTarget.gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#if CURVEDUI_STEAMVR_2
|
|||
|
//Get action and their paths to show in the popup.
|
|||
|
steamVRActions = SteamVR_Input.GetActions<SteamVR_Action_Boolean>();
|
|||
|
steamVRActionsPaths = new string[] { "None" };
|
|||
|
if (steamVRActions != null && steamVRActions.Length > 0)
|
|||
|
{
|
|||
|
List<string> enumList = new List<string>();
|
|||
|
|
|||
|
//add all action paths to list.
|
|||
|
for (int i = 0; i < steamVRActions.Length; i++)
|
|||
|
enumList.Add(steamVRActions[i].fullPath);
|
|||
|
|
|||
|
enumList.Add("None"); //need a way to null that field, so add None as last pick.
|
|||
|
|
|||
|
//replace forward slashes with backslack instead. Otherwise they will not show up.
|
|||
|
for (int index = 0; index < enumList.Count; index++)
|
|||
|
enumList[index] = enumList[index].Replace('/', '\\');
|
|||
|
|
|||
|
steamVRActionsPaths = enumList.ToArray();
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public override void OnInspectorGUI()
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//initial settings------------------------------------//
|
|||
|
CurvedUISettings myTarget = (CurvedUISettings)target;
|
|||
|
if (target == null) return;
|
|||
|
GUI.changed = false;
|
|||
|
EditorGUIUtility.labelWidth = 150;
|
|||
|
#if UNITY_2018_3_OR_NEWER
|
|||
|
inPrefabMode = (UnityEditor.SceneManagement.PrefabStageUtility.GetCurrentPrefabStage() != null);
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
//Version----------------------------------------------//
|
|||
|
GUILayout.Label("Version " + CurvedUISettings.Version, EditorStyles.miniLabel);
|
|||
|
|
|||
|
|
|||
|
//Warnings------------------------------------------//
|
|||
|
//Canvas is on layer that is not part of RaycastLayerMask
|
|||
|
if(!IsInLayerMask(myTarget.gameObject.layer, CurvedUIInputModule.Instance.RaycastLayerMask) && myTarget.Interactable)
|
|||
|
{
|
|||
|
EditorGUILayout.HelpBox(WarningLayerNotIncluded, MessageType.Error);
|
|||
|
GUILayout.Space(30);
|
|||
|
}
|
|||
|
|
|||
|
//Improper event system warning
|
|||
|
if (CUIeventSystemPresent == false)
|
|||
|
{
|
|||
|
EditorGUILayout.HelpBox("Unity UI may become unresponsive in VR if game window loses focus. " +
|
|||
|
"Use CurvedUIEventSystem instead of standard EventSystem component to solve this issue.",
|
|||
|
MessageType.Warning);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(146);
|
|||
|
if (GUILayout.Button("Use CurvedUI Event System")) SwapEventSystem();
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
GUILayout.Space(30);
|
|||
|
}
|
|||
|
//-----------------------------------------------------//
|
|||
|
|
|||
|
|
|||
|
//Control methods--------------------------------------//
|
|||
|
DrawControlMethods();
|
|||
|
|
|||
|
|
|||
|
//shape settings----------------------------------------//
|
|||
|
GUILayout.Label("Shape", EditorStyles.boldLabel);
|
|||
|
myTarget.Shape = (CurvedUISettings.CurvedUIShape)EditorGUILayout.EnumPopup("Canvas Shape", myTarget.Shape);
|
|||
|
switch (myTarget.Shape)
|
|||
|
{
|
|||
|
case CurvedUISettings.CurvedUIShape.CYLINDER:
|
|||
|
{
|
|||
|
myTarget.Angle = EditorGUILayout.IntSlider("Angle", myTarget.Angle, -360, 360);
|
|||
|
myTarget.PreserveAspect = EditorGUILayout.Toggle("Preserve Aspect", myTarget.PreserveAspect);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
case CurvedUISettings.CurvedUIShape.CYLINDER_VERTICAL:
|
|||
|
{
|
|||
|
myTarget.Angle = EditorGUILayout.IntSlider("Angle", myTarget.Angle, -360, 360);
|
|||
|
myTarget.PreserveAspect = EditorGUILayout.Toggle("Preserve Aspect", myTarget.PreserveAspect);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
case CurvedUISettings.CurvedUIShape.RING:
|
|||
|
{
|
|||
|
myTarget.RingExternalDiameter = Mathf.Clamp(EditorGUILayout.IntField("External Diameter", myTarget.RingExternalDiameter), 1, 100000);
|
|||
|
myTarget.Angle = EditorGUILayout.IntSlider("Angle", myTarget.Angle, 0, 360);
|
|||
|
myTarget.RingFill = EditorGUILayout.Slider("Fill", myTarget.RingFill, 0.0f, 1.0f);
|
|||
|
myTarget.RingFlipVertical = EditorGUILayout.Toggle("Flip Canvas Vertically", myTarget.RingFlipVertical);
|
|||
|
break;
|
|||
|
}
|
|||
|
case CurvedUISettings.CurvedUIShape.SPHERE:
|
|||
|
{
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(150);
|
|||
|
EditorGUILayout.HelpBox("Sphere shape is more expensive than a Cylinder shape. Keep this in mind when working on mobile VR.", MessageType.Info);
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
GUILayout.Space(10);
|
|||
|
|
|||
|
if (myTarget.PreserveAspect)
|
|||
|
{
|
|||
|
myTarget.Angle = EditorGUILayout.IntSlider("Angle", myTarget.Angle, -360, 360);
|
|||
|
}
|
|||
|
else {
|
|||
|
myTarget.Angle = EditorGUILayout.IntSlider("Horizontal Angle", myTarget.Angle, 0, 360);
|
|||
|
myTarget.VerticalAngle = EditorGUILayout.IntSlider("Vertical Angle", myTarget.VerticalAngle, 0, 180);
|
|||
|
}
|
|||
|
|
|||
|
myTarget.PreserveAspect = EditorGUILayout.Toggle("Preserve Aspect", myTarget.PreserveAspect);
|
|||
|
break;
|
|||
|
}
|
|||
|
}//end of shape settings-------------------------------//
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//180 degree warning ----------------------------------//
|
|||
|
if ((myTarget.Shape != CurvedUISettings.CurvedUIShape.RING && myTarget.Angle.Abs() > 180) ||
|
|||
|
(myTarget.Shape == CurvedUISettings.CurvedUIShape.SPHERE && myTarget.VerticalAngle > 180))
|
|||
|
Draw180DegreeWarning();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
//advanced settings------------------------------------//
|
|||
|
GUILayout.Space(30);
|
|||
|
if (!ShowAdvaced)
|
|||
|
{
|
|||
|
if (GUILayout.Button("Show Advanced Settings"))
|
|||
|
{
|
|||
|
ShowAdvaced = true;
|
|||
|
loadingCustomDefine = false;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//hide advances settings button.
|
|||
|
if (GUILayout.Button("Hide Advanced Settings")) ShowAdvaced = false;
|
|||
|
GUILayout.Space(20);
|
|||
|
|
|||
|
//InputModule Options - only if we're not in prefab mode.
|
|||
|
if (!inPrefabMode)
|
|||
|
{
|
|||
|
CurvedUIInputModule.Instance.RaycastLayerMask = LayerMaskField("Raycast Layer Mask",
|
|||
|
CurvedUIInputModule.Instance.RaycastLayerMask);
|
|||
|
|
|||
|
//pointer override
|
|||
|
GUILayout.Space(20);
|
|||
|
CurvedUIInputModule.Instance.PointerTransformOverride = (Transform)EditorGUILayout.ObjectField("Pointer Override", CurvedUIInputModule.Instance.PointerTransformOverride, typeof(Transform), true);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(150);
|
|||
|
GUILayout.Label("(Optional) If set, its position and forward (blue) direction will be used to point at canvas.", EditorStyles.helpBox);
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
EditorGUILayout.HelpBox("Some settings are hidden in Prefab Mode", MessageType.Warning);
|
|||
|
}
|
|||
|
|
|||
|
//quality
|
|||
|
GUILayout.Space(20);
|
|||
|
myTarget.Quality = EditorGUILayout.Slider("Quality", myTarget.Quality, 0.1f, 3.0f);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(150);
|
|||
|
GUILayout.Label("Smoothness of the curve. Bigger values mean more subdivisions. Decrease for better performance. Default 1", EditorStyles.helpBox);
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
|
|||
|
//common options
|
|||
|
myTarget.Interactable = EditorGUILayout.Toggle("Interactable", myTarget.Interactable);
|
|||
|
myTarget.BlocksRaycasts = EditorGUILayout.Toggle("Blocks Raycasts", myTarget.BlocksRaycasts);
|
|||
|
if (myTarget.Shape != CurvedUISettings.CurvedUIShape.SPHERE) myTarget.ForceUseBoxCollider =
|
|||
|
EditorGUILayout.Toggle("Force Box Colliders Use", myTarget.ForceUseBoxCollider);
|
|||
|
|
|||
|
//add components button
|
|||
|
GUILayout.Space(20);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Label("Components", GUILayout.Width(146));
|
|||
|
if (GUILayout.Button("Add Curved Effect To Children")) AddCurvedUIComponents();
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
|
|||
|
//remove components button
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Label("", GUILayout.Width(146));
|
|||
|
if (!ShowRemoveCurvedUI)
|
|||
|
{
|
|||
|
if (GUILayout.Button("Remove CurvedUI from Canvas")) ShowRemoveCurvedUI = true;
|
|||
|
}
|
|||
|
else {
|
|||
|
if (GUILayout.Button("Remove CurvedUI")) RemoveCurvedUIComponents();
|
|||
|
if (GUILayout.Button("Cancel")) ShowRemoveCurvedUI = false;
|
|||
|
}
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
|
|||
|
//documentation link
|
|||
|
GUILayout.Space(20);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Label("Documentation", GUILayout.Width(146));
|
|||
|
if (GUILayout.Button("Open in web browser")) Help.BrowseURL("https://docs.google.com/document/d/10hNcvOMissNbGgjyFyV1MS7HwkXXE6270A6Ul8h8pnQ/edit");
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
|
|||
|
}//end of Advanced settings---------------------------//
|
|||
|
|
|||
|
GUILayout.Space(20);
|
|||
|
|
|||
|
//final settings
|
|||
|
if (GUI.changed && myTarget != null)
|
|||
|
EditorUtility.SetDirty(myTarget);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#region CUSTOM GUI ELEMENTS
|
|||
|
void DrawControlMethods()
|
|||
|
{
|
|||
|
GUILayout.Label("Global Settings", EditorStyles.boldLabel);
|
|||
|
|
|||
|
//Do not allow to change Global Settings in Prefab Mode
|
|||
|
//These are stored in CurvedUInputModule
|
|||
|
if (inPrefabMode)
|
|||
|
{
|
|||
|
EditorGUILayout.HelpBox(
|
|||
|
"Some global settings (including Control Method) are hidden in Prefab Mode. These are stored on CurvedUIInputModule component which cannot be accessed now.",
|
|||
|
MessageType.Warning);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//Control Method dropdown--------------------------------//
|
|||
|
CurvedUIInputModule.ControlMethod = (CurvedUIInputModule.CUIControlMethod)EditorGUILayout.EnumPopup("Control Method", CurvedUIInputModule.ControlMethod);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(150);
|
|||
|
GUILayout.BeginVertical();
|
|||
|
|
|||
|
|
|||
|
//Custom Settings for each Control Method---------------//
|
|||
|
switch (CurvedUIInputModule.ControlMethod)
|
|||
|
{
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.MOUSE:
|
|||
|
{
|
|||
|
#if CURVEDUI_GOOGLEVR
|
|||
|
EditorGUILayout.HelpBox("Enabling this control method will disable GoogleVR support.", MessageType.Warning);
|
|||
|
DrawCustomDefineSwitcher("");
|
|||
|
#else
|
|||
|
GUILayout.Label("Basic Controller. Mouse on screen", EditorStyles.helpBox);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of MOUSE
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.GAZE:
|
|||
|
{
|
|||
|
#if CURVEDUI_GOOGLEVR
|
|||
|
EditorGUILayout.HelpBox("Enabling this control method will disable GoogleVR support.", MessageType.Warning);
|
|||
|
DrawCustomDefineSwitcher("");
|
|||
|
#else
|
|||
|
GUILayout.Label("Center of Canvas's Event Camera acts as a pointer. Can be used with any headset. If you're on cardboard, you can use it instead of GOOGLEVR control method.", EditorStyles.helpBox);
|
|||
|
CurvedUIInputModule.Instance.GazeUseTimedClick = EditorGUILayout.Toggle("Use Timed Click", CurvedUIInputModule.Instance.GazeUseTimedClick);
|
|||
|
if (CurvedUIInputModule.Instance.GazeUseTimedClick)
|
|||
|
{
|
|||
|
GUILayout.Label("Clicks a button if player rests his gaze on it for a period of time. You can assign an image to be used as a progress bar.", EditorStyles.helpBox);
|
|||
|
CurvedUIInputModule.Instance.GazeClickTimer = EditorGUILayout.FloatField("Click Timer (seconds)", CurvedUIInputModule.Instance.GazeClickTimer);
|
|||
|
CurvedUIInputModule.Instance.GazeClickTimerDelay = EditorGUILayout.FloatField("Timer Start Delay", CurvedUIInputModule.Instance.GazeClickTimerDelay);
|
|||
|
CurvedUIInputModule.Instance.GazeTimedClickProgressImage = (UnityEngine.UI.Image)EditorGUILayout.ObjectField("Progress Image To FIll", CurvedUIInputModule.Instance.GazeTimedClickProgressImage, typeof(UnityEngine.UI.Image), true);
|
|||
|
}
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of GAZE
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.WORLD_MOUSE:
|
|||
|
{
|
|||
|
|
|||
|
#if CURVEDUI_GOOGLEVR
|
|||
|
EditorGUILayout.HelpBox("Enabling this control method will disable GoogleVR support.", MessageType.Warning);
|
|||
|
DrawCustomDefineSwitcher("");
|
|||
|
#else
|
|||
|
GUILayout.Label("Mouse controller that is independent of the camera view. Use WorldSpaceMouseOnCanvas function to get its position.", EditorStyles.helpBox);
|
|||
|
CurvedUIInputModule.Instance.WorldSpaceMouseSensitivity = EditorGUILayout.FloatField("Mouse Sensitivity", CurvedUIInputModule.Instance.WorldSpaceMouseSensitivity);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of WORLD_MOUSE
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.CUSTOM_RAY:
|
|||
|
{
|
|||
|
#if CURVEDUI_GOOGLEVR
|
|||
|
EditorGUILayout.HelpBox("Enabling this control method will disable GoogleVR support.", MessageType.Warning);
|
|||
|
DrawCustomDefineSwitcher("");
|
|||
|
#else
|
|||
|
GUILayout.Label("Set a ray used to interact with canvas using CustomControllerRay function. Use CustomControllerButtonState bool to set button pressed state. Find both in CurvedUIInputModule class", EditorStyles.helpBox);
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
//GUILayout.Space(20);
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
if (GUILayout.Button("View code snippet")) Help.BrowseURL("https://docs.google.com/document/d/10hNcvOMissNbGgjyFyV1MS7HwkXXE6270A6Ul8h8pnQ/edit#heading=h.b164qm67xp15");
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of CUSTOM_RAY
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.STEAMVR_LEGACY:
|
|||
|
{
|
|||
|
#if CURVEDUI_STEAMVR_LEGACY
|
|||
|
// vive enabled, we can show settings
|
|||
|
GUILayout.Label("Use with SteamVR plugin 1.2 or below. Trigger acts a button", EditorStyles.helpBox);
|
|||
|
CurvedUIInputModule.Instance.UsedHand = (CurvedUIInputModule.Hand)EditorGUILayout.EnumPopup("Used Controller", CurvedUIInputModule.Instance.UsedHand);
|
|||
|
|
|||
|
#else
|
|||
|
GUILayout.Label("For SteamVR plugin 1.2 or below. Make sure you imported that SDK before enabling.", EditorStyles.helpBox);
|
|||
|
DrawCustomDefineSwitcher(ControlMethodDefineDict[CurvedUIInputModule.CUIControlMethod.STEAMVR_LEGACY]);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of STEAMVR_LEGACY
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.STEAMVR_2:
|
|||
|
{
|
|||
|
#if CURVEDUI_STEAMVR_2
|
|||
|
GUILayout.Label("Use SteamVR controllers to interact with canvas. Requires SteamVR Plugin 2.0 or later.", EditorStyles.helpBox);
|
|||
|
|
|||
|
|
|||
|
if(steamVRActions != null)
|
|||
|
{
|
|||
|
CurvedUIInputModule.Instance.UsedHand = (CurvedUIInputModule.Hand)EditorGUILayout.EnumPopup("Hand", CurvedUIInputModule.Instance.UsedHand);
|
|||
|
|
|||
|
//Find currently selected action in CurvedUIInputModule
|
|||
|
int curSelected = steamVRActionsPaths.Length - 1;
|
|||
|
for (int i = 0; i < steamVRActions.Length; i++)
|
|||
|
{
|
|||
|
//no action selected? select one that most likely deals with UI
|
|||
|
if(CurvedUIInputModule.Instance.SteamVRClickAction == null && steamVRActions[i].GetShortName().Contains("UI"))
|
|||
|
CurvedUIInputModule.Instance.SteamVRClickAction = steamVRActions[i];
|
|||
|
|
|||
|
//otherwise show currently selected
|
|||
|
if (steamVRActions[i] == CurvedUIInputModule.Instance.SteamVRClickAction) //otherwise show selected
|
|||
|
curSelected = i;
|
|||
|
}
|
|||
|
|
|||
|
//Show popup
|
|||
|
int newSelected = EditorGUILayout.Popup("Click With", curSelected, steamVRActionsPaths, EditorStyles.popup);
|
|||
|
|
|||
|
//assign selected SteamVR Action to CurvedUIInputMOdule
|
|||
|
if (curSelected != newSelected)
|
|||
|
{
|
|||
|
//none has been selected
|
|||
|
if (newSelected >= steamVRActions.Length)
|
|||
|
CurvedUIInputModule.Instance.SteamVRClickAction = null;
|
|||
|
else
|
|||
|
CurvedUIInputModule.Instance.SteamVRClickAction = steamVRActions[newSelected];
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//draw error
|
|||
|
EditorGUILayout.HelpBox("No SteamVR Actions set up. Configure your SteamVR plugin first in Window > Steam VR Input", MessageType.Error);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
#else
|
|||
|
GUILayout.Label("For SteamVR plugin 2.0 or above. Make sure you imported that SDK before enabling.", EditorStyles.helpBox);
|
|||
|
DrawCustomDefineSwitcher(ControlMethodDefineDict[CurvedUIInputModule.CUIControlMethod.STEAMVR_2]);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of STEAMVR_2
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.OCULUSVR:
|
|||
|
{
|
|||
|
#if CURVEDUI_OCULUSVR
|
|||
|
// oculus enabled, we can show settings
|
|||
|
GUILayout.Label("Use Rift, Quest, Go, or GearVR controller to interact with your canvas.", EditorStyles.helpBox);
|
|||
|
//hand property
|
|||
|
CurvedUIInputModule.Instance.UsedHand = (CurvedUIInputModule.Hand)EditorGUILayout.EnumPopup("Hand", CurvedUIInputModule.Instance.UsedHand);
|
|||
|
//button property
|
|||
|
CurvedUIInputModule.Instance.OculusTouchInteractionButton = (OVRInput.Button)EditorGUILayout.EnumPopup("Interaction Button", CurvedUIInputModule.Instance.OculusTouchInteractionButton);
|
|||
|
#else
|
|||
|
GUILayout.Label("Make sure you imported the SDK before enabling.", EditorStyles.helpBox);
|
|||
|
DrawCustomDefineSwitcher(ControlMethodDefineDict[CurvedUIInputModule.CUIControlMethod.OCULUSVR]);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of OCULUSVR
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.UNITY_XR:
|
|||
|
{
|
|||
|
#if CURVEDUI_UNITY_XR
|
|||
|
// oculus enabled, we can show settings
|
|||
|
GUILayout.Label("Use Unity XR Toolkit to interact with the canvas. You can choose UI button on the XRController itself.", EditorStyles.helpBox);
|
|||
|
//hand property
|
|||
|
CurvedUIInputModule.Instance.UsedHand = (CurvedUIInputModule.Hand)EditorGUILayout.EnumPopup("Hand", CurvedUIInputModule.Instance.UsedHand);
|
|||
|
//assign controllers
|
|||
|
CurvedUIInputModule.Instance.RightXRController = (UnityEngine.XR.Interaction.Toolkit.XRController)EditorGUILayout.ObjectField("Right Controller",
|
|||
|
CurvedUIInputModule.Instance.RightXRController, typeof(UnityEngine.XR.Interaction.Toolkit.XRController), true);
|
|||
|
CurvedUIInputModule.Instance.LeftXRController = (UnityEngine.XR.Interaction.Toolkit.XRController)EditorGUILayout.ObjectField("Left Controller",
|
|||
|
CurvedUIInputModule.Instance.LeftXRController, typeof(UnityEngine.XR.Interaction.Toolkit.XRController), true);
|
|||
|
#else
|
|||
|
GUILayout.Label("Make sure you imported Unity XR Toolkit before enabling.", EditorStyles.helpBox);
|
|||
|
DrawCustomDefineSwitcher(ControlMethodDefineDict[CurvedUIInputModule.CUIControlMethod.UNITY_XR]);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of UNITY_XR
|
|||
|
|
|||
|
|
|||
|
|
|||
|
case CurvedUIInputModule.CUIControlMethod.GOOGLEVR:
|
|||
|
{
|
|||
|
#if CURVEDUI_GOOGLEVR
|
|||
|
GUILayout.Label("Use GoogleVR Reticle to interact with canvas. Requires GoogleVR SDK 1.200.1 or later. Make sure you imported the SDK before enabling.", EditorStyles.helpBox);
|
|||
|
#else
|
|||
|
GUILayout.Label("Make sure you imported the GoogleVR SDK before enabling.", EditorStyles.helpBox);
|
|||
|
DrawCustomDefineSwitcher(ControlMethodDefineDict[CurvedUIInputModule.CUIControlMethod.GOOGLEVR]);
|
|||
|
#endif
|
|||
|
break;
|
|||
|
}// end of GOOGLEVR
|
|||
|
|
|||
|
|
|||
|
}//end of CUIControlMethod Switch
|
|||
|
|
|||
|
GUILayout.EndVertical();
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
GUILayout.Space(20);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Draws the define switcher for different control methods.
|
|||
|
/// Because different control methods use different API's that may not always be available,
|
|||
|
/// CurvedUI needs to be recompile with different custom defines to fix this. This method
|
|||
|
/// manages the defines.
|
|||
|
/// </summary>
|
|||
|
/// <param name="defineToSet">Switcho.</param>
|
|||
|
void DrawCustomDefineSwitcher(string defineToSet)
|
|||
|
{
|
|||
|
GUILayout.BeginVertical();
|
|||
|
GUILayout.Label("Press the [Enable] button to recompile scripts for this control method. Afterwards, you'll see more settings here.", EditorStyles.helpBox);
|
|||
|
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(50);
|
|||
|
if (GUILayout.Button(loadingCustomDefine ? "Please wait..." : "Enable."))
|
|||
|
{
|
|||
|
loadingCustomDefine = true;
|
|||
|
|
|||
|
//retrieve current defines
|
|||
|
string str = "";
|
|||
|
str += PlayerSettings.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
|
|||
|
|
|||
|
//remove unused curvedui defines - dictionary based.
|
|||
|
string define = "";
|
|||
|
foreach (var key in ControlMethodDefineDict.Keys)
|
|||
|
{
|
|||
|
define = ControlMethodDefineDict[key];
|
|||
|
|
|||
|
if (str.Contains(define))
|
|||
|
{
|
|||
|
if (str.Contains((";" + define)))
|
|||
|
str = str.Replace((";" + define), "");
|
|||
|
else
|
|||
|
str = str.Replace(define, "");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//add this one, if not present.
|
|||
|
if (defineToSet != "" && !str.Contains(defineToSet))
|
|||
|
str += ";" + defineToSet;
|
|||
|
|
|||
|
//Submit defines. This will cause recompilation
|
|||
|
PlayerSettings.SetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup, str);
|
|||
|
}
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
GUILayout.EndVertical();
|
|||
|
}
|
|||
|
|
|||
|
void Draw180DegreeWarning()
|
|||
|
{
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.Space(150);
|
|||
|
EditorGUILayout.HelpBox("Cavas with angle bigger than 180 degrees will not be interactable. \n" +
|
|||
|
"This is caused by Unity Event System requirements. Use two canvases facing each other for fully interactive 360 degree UI.", MessageType.Warning);
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
GUILayout.Space(10);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#region HELPER FUNCTIONS
|
|||
|
static List<string> layers;
|
|||
|
static string[] layerNames;
|
|||
|
|
|||
|
public static LayerMask LayerMaskField (string label, LayerMask selected)
|
|||
|
{
|
|||
|
if (layers == null) {
|
|||
|
layers = new List<string>();
|
|||
|
layerNames = new string[4];
|
|||
|
} else {
|
|||
|
layers.Clear ();
|
|||
|
}
|
|||
|
|
|||
|
int emptyLayers = 0;
|
|||
|
for (int i=0;i<32;i++) {
|
|||
|
string layerName = LayerMask.LayerToName (i);
|
|||
|
|
|||
|
if (layerName != "") {
|
|||
|
|
|||
|
for (;emptyLayers>0;emptyLayers--) layers.Add ("Layer "+(i-emptyLayers));
|
|||
|
layers.Add (layerName);
|
|||
|
} else {
|
|||
|
emptyLayers++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (layerNames.Length != layers.Count) {
|
|||
|
layerNames = new string[layers.Count];
|
|||
|
}
|
|||
|
for (int i=0;i<layerNames.Length;i++) layerNames[i] = layers[i];
|
|||
|
|
|||
|
selected.value = EditorGUILayout.MaskField (label,selected.value,layerNames);
|
|||
|
|
|||
|
return selected;
|
|||
|
}
|
|||
|
|
|||
|
bool IsInLayerMask(int layer, LayerMask layermask)
|
|||
|
{
|
|||
|
return layermask == (layermask | (1 << layer));
|
|||
|
}
|
|||
|
|
|||
|
Dictionary<CurvedUIInputModule.CUIControlMethod, string> ControlMethodDefineDict {
|
|||
|
get
|
|||
|
{
|
|||
|
if (m_controlMethodDefineDict == null)
|
|||
|
{
|
|||
|
m_controlMethodDefineDict = new Dictionary<CurvedUIInputModule.CUIControlMethod, string>();
|
|||
|
m_controlMethodDefineDict.Add(CurvedUIInputModule.CUIControlMethod.GOOGLEVR, "CURVEDUI_GOOGLEVR");
|
|||
|
m_controlMethodDefineDict.Add(CurvedUIInputModule.CUIControlMethod.STEAMVR_LEGACY, "CURVEDUI_STEAMVR_LEGACY");
|
|||
|
m_controlMethodDefineDict.Add(CurvedUIInputModule.CUIControlMethod.STEAMVR_2, "CURVEDUI_STEAMVR_2");
|
|||
|
m_controlMethodDefineDict.Add(CurvedUIInputModule.CUIControlMethod.OCULUSVR, "CURVEDUI_OCULUSVR");
|
|||
|
m_controlMethodDefineDict.Add(CurvedUIInputModule.CUIControlMethod.UNITY_XR, "CURVEDUI_UNITY_XR");
|
|||
|
}
|
|||
|
return m_controlMethodDefineDict;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void SwapEventSystem()
|
|||
|
{
|
|||
|
if (Application.isPlaying)
|
|||
|
{
|
|||
|
Debug.LogError("Cant do this in Play mode!");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
EventSystem system = FindObjectOfType<EventSystem>();
|
|||
|
if (!(system is CurvedUIEventSystem))
|
|||
|
{
|
|||
|
system.AddComponentIfMissing<CurvedUIEventSystem>();
|
|||
|
DestroyImmediate(system);
|
|||
|
}
|
|||
|
|
|||
|
CUIeventSystemPresent = true;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
///Travel the hierarchy and add CurvedUIVertexEffect to every gameobject that can be bent.
|
|||
|
/// </summary>
|
|||
|
private void AddCurvedUIComponents()
|
|||
|
{
|
|||
|
if (target == null) return;
|
|||
|
(target as CurvedUISettings).AddEffectToChildren();
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Removes all CurvedUI components from this canvas.
|
|||
|
/// </summary>
|
|||
|
private void RemoveCurvedUIComponents()
|
|||
|
{
|
|||
|
if (target == null) return;
|
|||
|
|
|||
|
//destroy TMP objects
|
|||
|
List<CurvedUITMP> tmps = new List<CurvedUITMP>();
|
|||
|
tmps.AddRange((target as CurvedUISettings).GetComponentsInChildren<CurvedUITMP>(true));
|
|||
|
for (int i = 0; i < tmps.Count; i++)
|
|||
|
{
|
|||
|
DestroyImmediate(tmps[i]);
|
|||
|
}
|
|||
|
|
|||
|
List<CurvedUITMPSubmesh> submeshes = new List<CurvedUITMPSubmesh>();
|
|||
|
submeshes.AddRange((target as CurvedUISettings).GetComponentsInChildren<CurvedUITMPSubmesh>(true));
|
|||
|
for (int i = 0; i < submeshes.Count; i++)
|
|||
|
{
|
|||
|
DestroyImmediate(submeshes[i]);
|
|||
|
}
|
|||
|
|
|||
|
//destroy curving componenets
|
|||
|
List<CurvedUIVertexEffect> comps = new List<CurvedUIVertexEffect>();
|
|||
|
comps.AddRange((target as CurvedUISettings).GetComponentsInChildren<CurvedUIVertexEffect>(true));
|
|||
|
for (int i = 0; i < comps.Count; i++)
|
|||
|
{
|
|||
|
if (comps[i].GetComponent<UnityEngine.UI.Graphic>() != null) comps[i].GetComponent<UnityEngine.UI.Graphic>().SetAllDirty();
|
|||
|
DestroyImmediate(comps[i]);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//destroy raycasters
|
|||
|
List<CurvedUIRaycaster> raycasters = new List<CurvedUIRaycaster>();
|
|||
|
raycasters.AddRange((target as CurvedUISettings).GetComponents<CurvedUIRaycaster>());
|
|||
|
for (int i = 0; i < raycasters.Count; i++)
|
|||
|
{
|
|||
|
DestroyImmediate(raycasters[i]);
|
|||
|
}
|
|||
|
|
|||
|
DestroyImmediate(target);
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
#region STRINGS
|
|||
|
private static string WarningLayerNotIncluded = "This Canvas' layer " +
|
|||
|
"is not included in the RaycastLayerMask. User will not be able to interact with it. " +
|
|||
|
"Add its layer to RaycastLayerMask below to fix it, or set the " +
|
|||
|
"Interactable property to False to dismiss this message.";
|
|||
|
#endregion
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|