private void HandleProperty(SerializedProperty prop) { if (prop.name.Equals("m_Script")) { return; } var disabledAttribute = UTUtils.GetPropertyAttribute <DisabledAttribute>(prop); propDisabled = false; if (disabledAttribute != null) { if (disabledAttribute.methodName != null) { propDisabled = UTUtils.GetVisibleThroughAttribute(prop, disabledAttribute.methodName, false); } else { propDisabled = true; } } if (prop.isArray && prop.propertyType != SerializedPropertyType.String) { HandleArray(prop); } else { EditorGUI.BeginChangeCheck(); EditorGUI.BeginDisabledGroup(propDisabled); EditorGUILayout.PropertyField(prop); EditorGUI.EndDisabledGroup(); if (!EditorGUI.EndChangeCheck()) { return; } var changeCallback = UTUtils.GetPropertyAttribute <OnValueChangedAttribute>(prop); if (changeCallback == null) { return; } var m = prop.serializedObject.targetObject.GetType().GetMethod(changeCallback.methodName, UTUtils.flags); if (m == null) { return; } if (m.GetParameters().Length > 1) { m.Invoke( serializedObject.targetObject, new object[] { serializedObject, prop }); } else { m.Invoke( serializedObject.targetObject, new object[] { prop }); } } propDisabled = false; }
private void RenderHelpBox(SerializedProperty prop) { var helpBoxAttr = UTUtils.GetPropertyAttribute <HelpBoxAttribute>(prop); if (helpBoxAttr != null) { if (helpBoxAttr.methodName.Length > 0 && !UTUtils.GetVisibleThroughAttribute(prop, helpBoxAttr.methodName, false)) { return; } UTStyles.RenderNote(helpBoxAttr.text); } }
public override void AfterGUI(SerializedProperty property) { if (methodName != "") { isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, false); } if (!isVisible) { return; } UTStyles.RenderNote(text); }
private void SetupLayers() { UTUtils.CreateLayer("CameraSystem", emptyLayer); for (int i = 0; i < 32; i++) { if (i == emptyLayer) { continue; } Physics.IgnoreLayerCollision(emptyLayer, i, true); } cameraPPLayer = emptyLayer; }
public override bool BeforeGUI(ref Rect position, SerializedProperty property, GUIContent label, bool visible) { isVisible = visible; if (!visible) { return(false); } if (methodName != "") { isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, false); } if (isVisible && property.name != "data" && property.depth == 0) { position.yMax -= boxHeight; } return(true); }
public override void AfterGUI(Rect position, SerializedProperty property, GUIContent label) { if (!isVisible) { return; } if (property.name == "data" && property.depth > 0) { return; } var rect = EditorGUI.IndentedRect(position); // check for section header var secHeader = UTUtils.GetPropertyAttribute <SectionHeaderAttribute>(property); rect.yMin += secHeader != null ? fieldHeight / 2 + 2 : fieldHeight + 2; rect.height = boxHeight; UTStyles.RenderNote(ref rect, text); }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { if (property.name == "data" && property.depth > 0) { EditorGUI.PropertyField(position, property, label); return; } var fieldType = property.serializedObject.targetObject.GetType().GetField(property.name).FieldType; var source = UTUtils.GetValueThroughAttribute(property, methodName, out var sourceValType); if (sourceType == PopupSource.Method && fieldType != sourceValType || property.type != "string") { EditorGUI.PropertyField(position, property, label); return; } if (sourceType == PopupSource.Animator) { options = UTUtils.GetAnimatorTriggers(source as Animator).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.UdonBehaviour) { options = UTUtils.GetUdonEvents(source as UdonSharpBehaviour).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.Shader) { options = UTUtils.GetShaderPropertiesByType(source, shaderPropType).Select(o => new GUIContent(o)).ToArray(); } else { options = ((string[])source).Select(o => new GUIContent(o)).ToArray(); } selectedIndex = options.ToList().FindIndex(i => i.text == property.stringValue); if (selectedIndex >= options.Length || selectedIndex < 0) { selectedIndex = 0; } var finalLabel = hideLabel ? new GUIContent() : label; selectedIndex = EditorGUI.Popup(position, finalLabel, selectedIndex, options); property.stringValue = options[selectedIndex].text; }
public UTBehaviourInfo(UdonSharpBehaviour targetBeh) { var targetType = targetBeh.GetType(); name = targetBeh.name; var cNameAttr = targetType.GetCustomAttributes(typeof(CustomNameAttribute)) .Select(i => i as CustomNameAttribute).ToArray(); customName = cNameAttr.Any() ? cNameAttr.First().name : null; var helpUrlAttr = targetType.GetCustomAttributes(typeof(HelpURLAttribute)) .Select(i => i as HelpURLAttribute).ToArray(); helpUrl = helpUrlAttr.Any() ? helpUrlAttr.First().URL : null; var helpMsgAttr = targetType.GetCustomAttributes(typeof(HelpMessageAttribute)) .Select(i => i as HelpMessageAttribute).ToArray(); helpMsg = helpMsgAttr.Any() ? helpMsgAttr.First().helpMessage : null; var onValChangedAttr = targetType.GetCustomAttributes(typeof(OnValuesChangedAttribute)) .Select(i => i as OnValuesChangedAttribute).ToArray(); onValuesChanged = onValChangedAttr.Any() ? targetType.GetMethod(onValChangedAttr.First().methodName) : null; var onBeforeEditorAttr = targetType.GetCustomAttributes(typeof(OnBeforeEditorAttribute)) .Select(i => i as OnBeforeEditorAttribute).ToArray(); onBeforeEditor = onBeforeEditorAttr.Any() ? targetType.GetMethod(onBeforeEditorAttr.First().methodName) : null; var onAfterEditorAttr = targetType.GetCustomAttributes(typeof(OnAfterEditorAttribute)) .Select(i => i as OnAfterEditorAttribute).ToArray(); onAfterEditor = onAfterEditorAttr.Any() ? targetType.GetMethod(onAfterEditorAttr.First().methodName) : null; udonCustomEvents = UTUtils.GetUdonEvents(targetBeh); if (udonCustomEvents.Length == 1 && udonCustomEvents.First() == "no events found") { udonCustomEvents = new string[0]; } buttons = targetType.GetMethods() .Where(i => i.GetCustomAttributes(typeof(ButtonAttribute)).Any()).ToArray(); }
private void RenderStackedArray(string name, SerializedProperty prop, SerializedProperty otherProp, PopupAttribute leftPopup, PopupAttribute rightPopup, string addMethod, string addText, string changedCallback) { var disabledString = propDisabled ? "[Read Only]" : ""; prop.isExpanded = UTStyles.FoldoutHeader($"{name} [{prop.arraySize}] {disabledString}", prop.isExpanded); var foldoutRect = GUILayoutUtility.GetLastRect(); if (!propDisabled) { HandleDragAndDrop(foldoutRect, prop, otherProp); if (droppedObjects) { return; } } if (!prop.isExpanded) { return; } EditorGUI.BeginDisabledGroup(propDisabled); for (int i = 0; i < prop.arraySize; i++) { EditorGUILayout.BeginHorizontal(); if (RenderPositionControls(i, new[] { prop, otherProp })) { break; } // this code is very similar to PopupAttribute itself // but we have to handle it here directly because we are connecting two different props together // should probably refactor at some point EditorGUI.BeginChangeCheck(); // handle arrays of different lengths var lLength = prop.arraySize; var rLength = otherProp.arraySize; if (lLength != rLength) { prop.arraySize = Math.Max(lLength, rLength); otherProp.arraySize = Math.Max(lLength, rLength); } // Left Field if (leftPopup == null) { EditorGUILayout.PropertyField(prop.GetArrayElementAtIndex(i), new GUIContent()); } else { var source = otherProp.GetArrayElementAtIndex(i); var options = UTUtils.GetPopupOptions(prop.GetArrayElementAtIndex(i), source, leftPopup, out var selectedIndex); selectedIndex = EditorGUILayout.Popup(selectedIndex, options); prop.GetArrayElementAtIndex(i).stringValue = options[selectedIndex]; } if (rightPopup == null) { EditorGUILayout.PropertyField(otherProp.GetArrayElementAtIndex(i), new GUIContent()); } else { var source = prop.GetArrayElementAtIndex(i); var options = UTUtils.GetPopupOptions(otherProp.GetArrayElementAtIndex(i), source, rightPopup, out var selectedIndex); selectedIndex = EditorGUILayout.Popup(selectedIndex, options); otherProp.GetArrayElementAtIndex(i).stringValue = options[selectedIndex]; } if (EditorGUI.EndChangeCheck()) { HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { prop.GetArrayElementAtIndex(i), otherProp.GetArrayElementAtIndex(i), i }); } if (RenderRemoveControls(i, new[] { prop, otherProp })) { HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { null, null, i }); break; } EditorGUILayout.EndHorizontal(); } if (!propDisabled) { EditorGUILayout.BeginHorizontal(); if (RenderAddControls(new[] { prop, otherProp }, addText, addMethod)) { HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { prop.GetArrayElementAtIndex(prop.arraySize - 1), otherProp.GetArrayElementAtIndex(otherProp.arraySize - 1), prop.arraySize - 1 }); } if (GUILayout.Button("Clear", GUILayout.MaxWidth(60))) { prop.arraySize = 0; otherProp.arraySize = 0; HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { null, null, 0 }); } EditorGUILayout.EndHorizontal(); } EditorGUI.EndDisabledGroup(); }
private void RenderArray(SerializedProperty prop, string changedCallback) { var formatted = Regex.Split(prop.name, @"(?<!^)(?=[A-Z])"); formatted[0] = formatted[0].Substring(0, 1).ToUpper() + formatted[0].Substring(1); var disabledString = propDisabled ? "[Read Only]" : ""; prop.isExpanded = UTStyles.FoldoutHeader($"{String.Join(" ", formatted)} [{prop.arraySize}] {disabledString}", prop.isExpanded); var foldoutRect = GUILayoutUtility.GetLastRect(); if (!propDisabled) { HandleDragAndDrop(foldoutRect, prop); if (droppedObjects) { return; } } if (!prop.isExpanded) { return; } EditorGUI.BeginDisabledGroup(propDisabled); var popup = UTUtils.GetPropertyAttribute <PopupAttribute>(prop); for (int i = 0; i < prop.arraySize; i++) { EditorGUILayout.BeginHorizontal(); if (RenderPositionControls(i, new[] { prop })) { break; } EditorGUI.BeginChangeCheck(); if (popup == null) { EditorGUILayout.PropertyField(prop.GetArrayElementAtIndex(i), new GUIContent()); } else { var options = UTUtils.GetPopupOptions(prop.GetArrayElementAtIndex(i), null, popup, out var selectedIndex); selectedIndex = EditorGUILayout.Popup(selectedIndex, options); prop.GetArrayElementAtIndex(i).stringValue = options[selectedIndex]; } if (EditorGUI.EndChangeCheck()) { HandleChangeCallback(t, changedCallback, prop, null, new object[] { prop.GetArrayElementAtIndex(i), i }); } if (RenderRemoveControls(i, new[] { prop })) { HandleChangeCallback(t, changedCallback, prop, null, new object[] { null, i }); break; } EditorGUILayout.EndHorizontal(); } if (!propDisabled) { EditorGUILayout.BeginHorizontal(); if (RenderAddControls(new[] { prop }, "Add Element", null)) { HandleChangeCallback(t, changedCallback, prop, null, new object[] { prop.GetArrayElementAtIndex(prop.arraySize - 1), prop.arraySize - 1 }); } if (GUILayout.Button("Clear", GUILayout.MaxWidth(60))) { prop.arraySize = 0; HandleChangeCallback(t, changedCallback, prop, null, new object[] { null, 0 }); } EditorGUILayout.EndHorizontal(); } EditorGUI.EndDisabledGroup(); }
private void HandleArray(SerializedProperty prop) { var attrs = UTUtils.GetPropertyAttributes(prop); var modifierAttrs = UTUtils.GetPropertyAttributes <Attribute>(prop); var isGroup = attrs.Where(a => a is ListViewAttribute).ToArray().Length > 0; var groupAttribute = attrs.Select(a => a as ListViewAttribute).ToArray(); var onValueChangedAttribute = UTUtils.GetPropertyAttribute <OnValueChangedAttribute>(prop); // hideIf attribute var hideIfAttribute = modifierAttrs.OfType <HideIfAttribute>().ToArray(); var isHidden = hideIfAttribute.Length > 0 && UTUtils.GetVisibleThroughAttribute(prop, hideIfAttribute[0].methodName, false); // handling for regular arrays, make nicer down the line if (!isGroup) { if (isHidden) { return; } RenderArray(prop, onValueChangedAttribute?.methodName); if (droppedObjects) { return; } RenderHelpBox(prop); return; } var groupName = groupAttribute[0].name; var items = cT.GetFields().Where(f => f.GetAttribute <ListViewAttribute>() != null && f.GetAttribute <ListViewAttribute>().name == groupName) .ToList(); // fast exit on 1 element with list view if (items.Count < 2) { if (isHidden) { return; } RenderArray(prop, onValueChangedAttribute?.methodName); if (droppedObjects) { return; } RenderHelpBox(prop); return; } var index = items.FindIndex(a => a.Name == prop.name); if (index > 0) { return; } var sectionHeaderAttribute = UTUtils.GetPropertyAttribute <SectionHeaderAttribute>(prop); if (sectionHeaderAttribute != null) { UTStyles.RenderSectionHeader(sectionHeaderAttribute.text); } if (isHidden) { return; } var otherProp = serializedObject.FindProperty(items[1].Name); var leftPopupAttribute = UTUtils.GetPropertyAttribute <PopupAttribute>(prop); var rightPopupAttribute = UTUtils.GetPropertyAttribute <PopupAttribute>(otherProp); if (rightPopupAttribute != null || leftPopupAttribute != null) { RenderStackedArray(groupAttribute[0].name, prop, otherProp, leftPopupAttribute, rightPopupAttribute, groupAttribute[0].addMethodName, groupAttribute[0].addButtonText, onValueChangedAttribute?.methodName); if (droppedObjects) { return; } RenderHelpBox(prop); return; } RenderStackedArray(groupAttribute[0].name, prop, otherProp, groupAttribute[0].addMethodName, groupAttribute[0].addButtonText, onValueChangedAttribute?.methodName); if (droppedObjects) { return; } RenderHelpBox(prop); }
public override bool GetVisible(SerializedProperty property) { isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, true); return(isVisible); }
public override bool BeforeGUI(ref Rect position, SerializedProperty property, GUIContent label, bool visible) { isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, true); return(isVisible); }
public override void OnInspectorGUI() { t = (UdonSharpBehaviour)target; showUdonSettings = (bool)(UTUtils.GetUTSetting("showUdonSettings", UTUtils.UTSettingType.Bool) ?? false); // we force-disable collision transfer for toolkit driven behaviours as it is not applicable if (!nonUBChecked) { nonUBMode = t.gameObject.GetComponent <UdonBehaviour>() == null; nonUBChecked = true; } if (!nonUBMode) { if (UdonSharpEditorUtility.GetBackingUdonBehaviour(t).AllowCollisionOwnershipTransfer) { UdonSharpEditorUtility.GetBackingUdonBehaviour(t).AllowCollisionOwnershipTransfer = false; } } var headerExited = false; EditorGUI.BeginChangeCheck(); showUdonSettings = GUILayout.Toggle(showUdonSettings, "Udon Settings", UTStyles.smallButton); if (EditorGUI.EndChangeCheck()) { UTUtils.SetUTSetting("showUdonSettings", UTUtils.UTSettingType.Bool, showUdonSettings); } if (showUdonSettings) { headerExited = UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(t, true); } if (headerExited) { return; } #region Caching if (!cacheBuilt) { tT = t.GetType(); programAsset = UdonSharpEditorUtility.GetUdonSharpProgramAsset(t); behInfo = new UTBehaviourInfo(t); var prop = serializedObject.GetIterator(); var next = prop.NextVisible(true); if (next) { do { if (prop.name == "m_Script") { continue; } if (!fieldCache.ContainsKey(prop.name)) { var newField = new UTField(prop); fieldCache.Add(prop.name, newField); if (newField.isInTabGroup) { if (!tabs.ContainsKey(newField.tabGroupName)) { tabs.Add(newField.tabGroupName, new Dictionary <string, UTFieldType>()); // we only support one tab group per behaviour right now if (!tabsExist) { fieldOrder.Add(newField.tabGroupName, UTFieldType.Tab); tabsExist = true; } } // since tabs can host foldouts - we need to explicitly retarget them // this logic could be generalized if i ever want to make all of this recursive if (newField.isInFoldout) { if (!foldouts.ContainsKey(newField.foldoutName)) { foldouts.Add(newField.foldoutName, new Dictionary <string, UTFieldType>()); tabs[newField.tabGroupName].Add(newField.foldoutName, UTFieldType.Foldout); } AddToFieldOrder(newField, prop, true); continue; } AddToFieldOrder(newField, prop, addToTabGroup: true); continue; } if (newField.isInFoldout) { if (!foldouts.ContainsKey(newField.foldoutName)) { foldouts.Add(newField.foldoutName, new Dictionary <string, UTFieldType>()); fieldOrder.Add(newField.foldoutName, UTFieldType.Foldout); } AddToFieldOrder(newField, prop, true); continue; } AddToFieldOrder(newField, prop); } } while (prop.NextVisible(false)); } cacheBuilt = true; return; } var e = Event.current; if (e.type == EventType.Repaint) { if (firstRepaint) { firstRepaint = false; return; } } #endregion if (behInfo.customName != null || behInfo.helpUrl != null) { EditorGUILayout.BeginHorizontal(); UTStyles.RenderHeader(behInfo.customName != null ? behInfo.customName : behInfo.name); if (behInfo.helpUrl != null) { if (GUILayout.Button("?", GUILayout.Height(26), GUILayout.Width(26))) { Application.OpenURL(behInfo.helpUrl); } } EditorGUILayout.EndHorizontal(); } if (behInfo.helpMsg != null) { UTStyles.RenderNote(behInfo.helpMsg); } if (behInfo.onBeforeEditor != null) { behInfo.onBeforeEditor.Invoke(t, new object[] { serializedObject }); } // handle jagged arrays Undo.RecordObject(t, "Change Properties"); EditorGUI.BeginChangeCheck(); droppedObjects = false; // this method is overrideable by custom code DrawGUI(); if (EditorGUI.EndChangeCheck() || droppedObjects || shouldReserialize) { if (behInfo.onValuesChanged != null) { behInfo.onValuesChanged.Invoke(t, new object[] { serializedObject }); } serializedObject.ApplyModifiedProperties(); } if (droppedObjects) { return; } if (behInfo.onAfterEditor != null) { behInfo.onAfterEditor.Invoke(t, new object[] { serializedObject }); } #region Buttons if (behInfo.buttons != null && !Application.isPlaying && behInfo.buttons.Length > 0) { buttonsExpanded = UTStyles.FoldoutHeader("Editor Methods", buttonsExpanded); if (buttonsExpanded) { EditorGUILayout.BeginVertical(new GUIStyle("helpBox")); foreach (var button in behInfo.buttons) { if (GUILayout.Button(button.Name)) { button.Invoke(t, new object[] {}); } } EditorGUILayout.EndVertical(); } } if (Application.isPlaying && behInfo.udonCustomEvents.Length > 0 && !nonUBMode) { methodsExpanded = UTStyles.FoldoutHeader("Udon Events", methodsExpanded); if (methodsExpanded) { EditorGUILayout.BeginVertical(new GUIStyle("helpBox")); var rowBreak = Mathf.Max(1, Mathf.Min(3, behInfo.udonCustomEvents.Length - 1)); var rowEndI = -100; foreach (var(button, i) in behInfo.udonCustomEvents.WithIndex()) { if (i == rowEndI && i != behInfo.udonCustomEvents.Length - 1) { EditorGUILayout.EndHorizontal(); } if (i % rowBreak == 0 && i != behInfo.udonCustomEvents.Length - 1) { EditorGUILayout.BeginHorizontal(); rowEndI = Math.Min(i + rowBreak, behInfo.udonCustomEvents.Length - 1); } if (GUILayout.Button(button)) { UdonSharpEditorUtility.GetBackingUdonBehaviour(t).SendCustomEvent(button); UdonSharpEditorUtility.CopyUdonToProxy(t); } if (i == behInfo.udonCustomEvents.Length - 1 && rowEndI != -100) { EditorGUILayout.EndHorizontal(); } } EditorGUILayout.EndVertical(); } } #endregion }
public override void OnGUI(SerializedProperty property) { var source = UTUtils.GetValueThroughAttribute(property, methodName, out var sourceValType); if (property.name == "data" && sourceType == PopupSource.Method && property.type != "string" && property.type != "int") { EditorGUILayout.PropertyField(property, new GUIContent(property.displayName)); return; } if (property.name != "data") { var fieldType = property.serializedObject.targetObject.GetType().GetField(property.name).FieldType; if (sourceType == PopupSource.Method && fieldType != sourceValType && property.type != "string" && property.type != "int") { EditorGUILayout.PropertyField(property, new GUIContent(property.displayName)); return; } } var numericPopup = property.type == "int" && sourceValType == typeof(int) || property.type == "float" && sourceValType == typeof(float); if (sourceType == PopupSource.AnimatorTrigger) { options = UTUtils.GetAnimatorTriggers(source as Animator).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.AnimatorBool) { options = UTUtils.GetAnimatorBools(source as Animator).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.AnimatorFloat) { options = UTUtils.GetAnimatorFloats(source as Animator).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.AnimatorInt) { options = UTUtils.GetAnimatorInts(source as Animator).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.UdonBehaviour) { options = UTUtils.GetUdonEvents(source as UdonSharpBehaviour).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.UdonProgramVariable) { options = UTUtils.GetUdonVariables(source as UdonSharpBehaviour).Select(o => new GUIContent(o)).ToArray(); } else if (sourceType == PopupSource.Shader) { if (shaderPropType == ShaderPropType.All) { options = UTUtils.GetAllShaderProperties(source).Select(o => new GUIContent(o)).ToArray(); } else { options = UTUtils.GetShaderPropertiesByType(source, shaderPropType).Select(o => new GUIContent(o)).ToArray(); } } else { if (sourceValType == typeof(int)) { options = ((int[])source).Select(i => new GUIContent(i.ToString())).ToArray(); } else if (sourceValType == typeof(float)) { options = ((float[])source).Select(i => new GUIContent(i.ToString())).ToArray(); } else { options = ((string[])source).Select(o => new GUIContent(o)).ToArray(); } } // we want to still support int[] -> int[] and float[] -> float[] mapping if (property.type == "int" && !numericPopup) { selectedIndex = property.intValue; } else if (numericPopup) { if (property.type == "int") { selectedIndex = options.ToList().FindIndex(i => i.text == property.intValue.ToString()); } else { selectedIndex = options.ToList().FindIndex(i => i.text == property.floatValue.ToString()); } if (selectedIndex >= options.Length || selectedIndex < 0) { selectedIndex = 0; } } else { selectedIndex = options.ToList().FindIndex(i => i.text == property.stringValue); if (selectedIndex >= options.Length || selectedIndex < 0) { selectedIndex = 0; } } var finalLabel = hideLabel || property.name == "data" ? new GUIContent() : new GUIContent(property.displayName); selectedIndex = EditorGUILayout.Popup(finalLabel, selectedIndex, options); if (property.type == "int" && !numericPopup) { property.intValue = selectedIndex; } else if (numericPopup) { if (property.type == "int") { property.intValue = Convert.ToInt32(options[selectedIndex].text); } else { property.floatValue = Convert.ToSingle(options[selectedIndex].text); } } else { property.stringValue = options[selectedIndex].text; } }
private void OnGUI() { emptyLayer = 0; UTUtils.GetLayerMasks(); UTStyles.RenderHeader("Camera System Setup"); UTStyles.RenderNote("This tool will set up a camera system in your scene, for more details on how to customize the camera - consult the documentation page."); if (GUILayout.Button("Documentation", GUILayout.ExpandWidth(true))) { Application.OpenURL(WikiURL); } UTStyles.RenderSectionHeader("Position and Style"); var newCameraSpot = (Transform)EditorGUILayout.ObjectField("Camera Position", cameraSpot, typeof(Transform), true); if (newCameraSpot != cameraSpot) { setup = false; } cameraSpot = newCameraSpot; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Watermark Overlay"); watermark = (Texture)EditorGUILayout.ObjectField(watermark, typeof(Texture), true); EditorGUILayout.EndHorizontal(); UTStyles.RenderNote("Overlay should be a 16:9 transparent texture"); addGuide = EditorGUILayout.Toggle("Add Camera Guide", addGuide); if (addGuide) { var newGuideStyle = (GuideStyle)EditorGUILayout.EnumPopup("Guide Panel Style", guideStyle); if (newGuideStyle != guideStyle || standObj == null || standObjEditor == null) { var standPath = newGuideStyle == GuideStyle.Futuristic ? SciFiStandPath : TikiStandPath; standObj = AssetDatabase.LoadAssetAtPath(GetAssetPath(standPath), typeof(object)); standObjEditor = UnityEditor.Editor.CreateEditor(standObj); } var r = GUILayoutUtility.GetRect(450, 150); standObjEditor.OnPreviewGUI(r, EditorStyles.helpBox); guideStyle = newGuideStyle; } UTStyles.RenderSectionHeader("PostProcessing and Collisions"); UTStyles.RenderNote("Layers are very important to the overall setup. Make sure you follow the instructions below"); layers.Clear(); for (int i = 0; i < 32; i++) { var layerName = LayerMask.LayerToName(i); if (layerName.Length > 0) { layers.Add($"[{i}] {layerName}"); } else { if (i > 22 && emptyLayer == 0) { emptyLayer = i; } layers.Add($"[{i}] -- not set --"); } } var layersArr = layers.ToArray(); if (emptyLayer != 0) { if (GUILayout.Button("Setup Layers")) { SetupLayers(); } UTStyles.RenderNote("It seems like you have empty layers available, UdonToolkit can set up everything for you if you click the button above"); UTStyles.HorizontalLine(); } cameraPPLayer = EditorGUILayout.Popup("Camera PP Layer", cameraPPLayer, layersArr); UTStyles.RenderNote("This layer will be used for detecting PP volumes for the Camera System"); if (cameraPPLayer == 22) { EditorGUILayout.HelpBox("It is crucial to not put Camera PP volumes on the same layer as the main PostProcessing, or your own view will be affected by the camera effects", MessageType.Warning); } if (setup) { var oldColor = GUI.backgroundColor; GUI.backgroundColor = Color.green; UTStyles.RenderNote("Camera system has been set up in the scene!"); GUI.backgroundColor = oldColor; } if (GUILayout.Button("Create Camera System", GUILayout.Height(30))) { RunCameraSetup(); } if (GUILayout.Button("Add Guide Stand Only", GUILayout.Height(20))) { AddGuide(); } }
private void DrawFieldElement(UTField field, SerializedProperty prop) { var propPath = prop.propertyPath; var arrIndex = Convert.ToInt32(field.isArray ? propPath.Substring(propPath.LastIndexOf("[") + 1, propPath.LastIndexOf("]") - propPath.LastIndexOf("[") - 1) : null); var customLabel = field.attributes.Find(i => i is ShowLabelAttribute) as ShowLabelAttribute; var uiAttrs = field.uiAttrs; var uiOverride = uiAttrs.Where(i => i.GetType().GetMethod("OnGUI")?.DeclaringType == i.GetType()).ToArray(); EditorGUI.BeginChangeCheck(); switch (prop.type) { case "bool": if (uiOverride.Any()) { uiOverride.First().OnGUI(prop); break; } if (customLabel == null) { EditorGUILayout.PropertyField(prop, new GUIContent(), GUILayout.MaxWidth(30)); } else { EditorGUILayout.PropertyField(prop, new GUIContent(customLabel.label ?? prop.displayName)); } break; default: // for list views we handle the UI separately due to how popup targeting works if (uiOverride.Any() && !field.isInListView) { uiOverride.First().OnGUI(prop); break; } var popupAttr = field.attributes.Find(i => i is PopupAttribute) as PopupAttribute; if (popupAttr != null) { var sourceProp = UTUtils.GetPropThroughAttribute(serializedObject, popupAttr.methodName); // I do not like this handling // need a way to determine if target is a part of the list view or not without breaking the bank var source = sourceProp == null ? null : !field.isInListView ? sourceProp : sourceProp.isArray && sourceProp.arraySize > arrIndex ? sourceProp.GetArrayElementAtIndex(arrIndex) : null; var options = UTUtils.GetPopupOptions(prop, source, popupAttr, out var selectedIndex); selectedIndex = EditorGUILayout.Popup(selectedIndex, options); // we force reserialize for cases of default values if (prop.type == "int") { if (prop.intValue != selectedIndex) { shouldReserialize = true; } prop.intValue = selectedIndex; } else { if (prop.stringValue != options[selectedIndex]) { shouldReserialize = true; } prop.stringValue = options[selectedIndex]; } break; } // if there are no popup attributes - still allow gui override if (uiOverride.Any(i => !(i is PopupAttribute))) { uiOverride.First(i => !(i is PopupAttribute)).OnGUI(prop); break; } if (customLabel == null) { EditorGUILayout.PropertyField(prop, new GUIContent()); } else { EditorGUILayout.PropertyField(prop, new GUIContent(customLabel.label ?? prop.displayName)); } break; } if (EditorGUI.EndChangeCheck() && field.onValueChaged != null) { if (!field.isInListView) { field.onValueChaged.Invoke(t, new object[] { prop }); return; } HandleFieldChangeArray(field, prop, arrIndex); } }