Beispiel #1
0
        public override bool BeforeGUI(ref Rect position, SerializedProperty property, GUIContent label, bool visible)
        {
            if (!visible)
            {
                return(false);
            }
            if (isInList)
            {
                return(true);
            }
            var lRect     = GUILayoutUtility.GetLastRect();
            var rect      = EditorGUI.IndentedRect(position);
            var fullWidth = EditorGUIUtility.currentViewWidth;

            rect.width = EditorGUIUtility.currentViewWidth;
            if (Math.Abs(fullWidth - lRect.width) > 0.1f)
            {
                rect.width -= fullWidth - lRect.width;
            }
            rect.height = mHeight;
            UTStyles.RenderSectionHeader(ref rect, text);
            position.yMin += mHeight + 3;

            return(true);
        }
Beispiel #2
0
 private void DrawDefaultGUI(UdonSharpBehaviour t)
 {
     if (UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(target, false, false))
     {
         return;
     }
     base.OnInspectorGUI();
     UTStyles.HorizontalLine();
     if (GUILayout.Button("Show UdonToolkit Inspector", UTStyles.smallButton))
     {
         drawDefaultInspector = false;
     }
 }
Beispiel #3
0
        public override void AfterGUI(SerializedProperty property)
        {
            if (methodName != "")
            {
                isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, false);
            }

            if (!isVisible)
            {
                return;
            }
            UTStyles.RenderNote(text);
        }
Beispiel #4
0
        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);
            }
        }
Beispiel #5
0
        private void OnGUI()
        {
            GUILayout.Box("", new GUIStyle(EditorStyles.helpBox)
            {
                normal = new GUIStyleState()
                {
                    background = UTStyles.Splash
                }
            }, GUILayout.Height(150));
            if (labelStyle == null)
            {
                labelStyle = new GUIStyle("BoldLabel")
                {
                    fontSize = 13
                };
            }

            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField("Welcome to UdonToolkit!", labelStyle);
            GUILayout.Label(@"Udon Toolkit is a project aimed at simplifying usage of Udon by providing a set of easy to use purpose-built behaviours, from generic triggers and actions, to more complete systems like Key Items, Cabinet Drawers, etc.

This also includes a system of attributes that allow you to utilize the same UI elements when building your own behaviours!

If you find that something is broken or works not as you would expect - please ping me in the discord server, or better - create an issue on github.", "WordWrappedMiniLabel", GUILayout.ExpandWidth(true));
            GUILayout.Space(10);
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Documentation", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(WikiURL);
            }
            if (GUILayout.Button("Github Repo", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(GithubURL);
            }
            if (GUILayout.Button("Discord Server", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(DiscordURL);
            }
            if (GUILayout.Button("Support UdonToolkit", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(PatreonURL);
            }
            EditorGUILayout.EndHorizontal();
            GUILayout.Space(2);
            UTStyles.RenderNote("This will only show once, you can open it again via Window / UdonToolkit / Show Startup Screen");
            EditorGUILayout.EndVertical();
        }
Beispiel #6
0
        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);
        }
Beispiel #7
0
        private void OnGUI()
        {
            if (labelStyle == null)
            {
                labelStyle = new GUIStyle("BoldLabel")
                {
                    fontSize = 13
                };
            }

            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField("Welcome to UdonToolkit!", labelStyle);
            GUILayout.Label(@"Udon Toolkit is built to serve as a foundation for your next Udon-based world. It contains a lot of useful behaviours from Area Triggers, to Player Teleporters and Followers.

Also included are various fully-featured systems, like a Camera System that adds an enhanced camera functionality to your world. 

The last part of the Udon Toolkit is an expansive attributes system that allows you to create complex UI for your behaviours the same way Udon Toolkit does.

If you find that something is broken or works not as you would expect - please ping me in the discord server, or better - create an issue on github.", "WordWrappedMiniLabel", GUILayout.ExpandWidth(true));
            GUILayout.Space(10);
            if (GUILayout.Button("Documentation", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(WikiURL);
            }
            if (GUILayout.Button("Github Repo", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(GithubURL);
            }
            if (GUILayout.Button("Discord Server", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(DiscordURL);
            }
            if (GUILayout.Button("Support UdonToolkit", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(PatreonURL);
            }
            GUILayout.Space(2);
            UTStyles.RenderNote("This will only show once, you can open it again via Window / UdonToolkit / Show Startup Screen");
            EditorGUILayout.EndVertical();
        }
Beispiel #8
0
 private void OnGUI()
 {
     UTStyles.RenderHeader("Camera System Setup");
     EditorGUILayout.HelpBox("Camera System requires PostProcessing, please install it by searching for PostProcessing in Window -> Package Manager", MessageType.Error);
 }
Beispiel #9
0
        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();
        }
Beispiel #10
0
        private void RenderStackedArray(string name, SerializedProperty prop, SerializedProperty otherProp,
                                        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;
                }

                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);
                }
                EditorGUILayout.PropertyField(prop.GetArrayElementAtIndex(i), new GUIContent());
                EditorGUILayout.PropertyField(otherProp.GetArrayElementAtIndex(i), new GUIContent());
                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(40)))
                {
                    prop.arraySize      = 0;
                    otherProp.arraySize = 0;
                    HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { null, null, 0 });
                }
                EditorGUILayout.EndHorizontal();
            }
            EditorGUI.EndDisabledGroup();
        }
Beispiel #11
0
        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();
        }
Beispiel #12
0
        public override void OnInspectorGUI()
        {
            droppedObjects = false;
            isPlaying      = !Application.isPlaying;
            t = (UdonSharpBehaviour)target;
            if (cT == null)
            {
                cT         = t.GetType();
                undoString = $"Update {cT.Name}";
            }

            if (drawDefaultInspector)
            {
                DrawDefaultGUI(t);
                return;
            }
            if (UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(t, true))
            {
                return;
            }
            // Header
            var customNameAttr = cT.GetCustomAttributes(typeof(CustomNameAttribute))
                                 .Select(i => i as CustomNameAttribute).ToArray();
            var helpUrlAttribute = cT.GetCustomAttributes(typeof(HelpURLAttribute))
                                   .Select(i => i as HelpURLAttribute).ToArray();

            if (customNameAttr.Any() || helpUrlAttribute.Any())
            {
                EditorGUILayout.BeginHorizontal();
                UTStyles.RenderHeader(customNameAttr.Any() ? customNameAttr[0].name : cT.Name.Replace("Controller", ""));
                if (helpUrlAttribute.Any())
                {
                    if (GUILayout.Button("?", GUILayout.Height(26), GUILayout.Width(26)))
                    {
                        Application.OpenURL(helpUrlAttribute[0].URL);
                    }
                }
                EditorGUILayout.EndHorizontal();
            }

            EditorGUI.BeginChangeCheck();
            serializedObject.Update();

            // Help Box
            var helpBoxAttr = cT.GetCustomAttributes(typeof(HelpMessageAttribute))
                              .Select(i => i as HelpMessageAttribute).ToArray();

            if (helpBoxAttr.Any())
            {
                UTStyles.RenderNote(helpBoxAttr[0]?.helpMessage);
            }

            // Check prefabs
            if (PrefabUtility.IsPartOfAnyPrefab(t.gameObject))
            {
                EditorGUILayout.HelpBox(
                    "Udon doesn't play well with Prefabs. " +
                    "It is recommended to unpack your prefabs when modifying any values.\n" +
                    "Right click the prefab and choose \"Unpack Prefab\"", MessageType.Warning);
            }

            // Before Editor Callback
            var beforeEditorCallback = cT.GetCustomAttribute <OnBeforeEditorAttribute>();

            if (beforeEditorCallback != null)
            {
                var m = cT.GetMethod(beforeEditorCallback.methodName);
                m?.Invoke(t, new object[] { serializedObject });
            }

            // for direct editing of fields in case of jagged arrays - we need to record changes
            Undo.RecordObject(t, undoString);

            // Actual GUI
            try {
                DrawGUI(t);
            } catch (Exception ex) {
                // for some reason unity likes to throw ExitGUI exceptions when looking up scene objects
                // even tho it doesnt throw them when you don't try-catch
                if (ex.GetType() != typeof(ExitGUIException))
                {
                    Debug.LogException(ex);
                }
            }

            // After Editor Callback
            var afterEditorCallback = cT.GetCustomAttribute <OnAfterEditorAttribute>();

            if (afterEditorCallback != null)
            {
                var m = cT.GetMethod(afterEditorCallback.methodName);
                m?.Invoke(t, new object[] { serializedObject });
            }

            if (EditorGUI.EndChangeCheck() || droppedObjects)
            {
                // Global Values Callback
                var globalEditorCallback = cT.GetCustomAttribute <OnValuesChangedAttribute>();
                if (globalEditorCallback != null)
                {
                    var m = cT.GetMethod(globalEditorCallback.methodName);
                    m?.Invoke(t, new object[] { serializedObject });
                }
                serializedObject.ApplyModifiedProperties();
            }

            if (droppedObjects)
            {
                return;
            }

            // Extra Methods
            var methods = cT.GetMethods(methodFlags).Where(i => i.GetCustomAttribute <ButtonAttribute>() != null).ToArray();
            var buttons = methods
                          .Select(i => i.GetCustomAttribute <ButtonAttribute>())
                          .Where(i => i != null)
                          .ToArray();

            if (buttons.Any())
            {
                UTStyles.RenderSectionHeader("Methods");
                var rowBreak = Mathf.Max(1, Mathf.Min(3, buttons.Length - 1));
                var rowEndI  = -100;
                foreach (var(button, i) in buttons.WithIndex())
                {
                    if (i == rowEndI && i != buttons.Length - 1)
                    {
                        EditorGUILayout.EndHorizontal();
                    }
                    if (i % rowBreak == 0 && i != buttons.Length - 1)
                    {
                        EditorGUILayout.BeginHorizontal();
                        rowEndI = Math.Min(i + rowBreak, buttons.Length - 1);
                    }
                    EditorGUI.BeginDisabledGroup(isPlaying && !button.activeInEditMode);
                    if (GUILayout.Button(button.text))
                    {
                        if (button.activeInEditMode)
                        {
                            methods[i].Invoke(t, new object[] {});
                        }
                        else
                        {
                            UdonSharpEditorUtility.GetProxyBehaviour(t.GetComponent <UdonBehaviour>()).SendCustomEvent(methods[i].Name);
                        }
                    }
                    EditorGUI.EndDisabledGroup();
                    if (i == buttons.Length - 1 && rowEndI != -100)
                    {
                        EditorGUILayout.EndHorizontal();
                    }
                }
            }

            UTStyles.HorizontalLine();
            if (GUILayout.Button("Show Default Inspector", UTStyles.smallButton))
            {
                drawDefaultInspector = true;
            }
        }
Beispiel #13
0
        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);
        }
Beispiel #14
0
        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
        }
Beispiel #15
0
 public override void BeforeGUI(SerializedProperty property)
 {
     UTStyles.RenderSectionHeader(text);
 }
Beispiel #16
0
        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();
            }
        }
Beispiel #17
0
        private void HandleListView(List <UTField> listViewFields, KeyValuePair <string, UTFieldType> fieldEntry)
        {
            List <SerializedProperty> propsList = new List <SerializedProperty>();

            foreach (var field in listViewFields)
            {
                propsList.Add(serializedObject.FindProperty(field.name));
            }

            // draw header
            var parentProp = serializedObject.FindProperty(listViewFields[0].name);
            var uiAttrs    = listViewFields[0].uiAttrs;

            var isVisible = true;

            foreach (var uiAttr in uiAttrs)
            {
                if (!uiAttr.GetVisible(parentProp))
                {
                    isVisible = false;
                    break;
                }
            }

            if (!isVisible)
            {
                return;
            }

            foreach (var uiAttr in uiAttrs)
            {
                uiAttr.BeforeGUI(propsList[0]);
            }

            var propDisabled = listViewFields.Exists(i => i.isDisabled);
            var page         = listPaginations[fieldEntry.Key];
            var pageCount    = Mathf.CeilToInt(parentProp.arraySize / 30f);

            if (pageCount > 1 && page > pageCount - 1)
            {
                page = pageCount - 1;
                listPaginations[fieldEntry.Key] = page;
            }


            var utilsShownVal = utilsShown[fieldEntry.Key];

            parentProp.isExpanded =
                UTStyles.FoldoutHeader(
                    GetListViewHeaderText(fieldEntry.Key, propDisabled, parentProp.isExpanded, page, pageCount,
                                          parentProp.arraySize),
                    parentProp.isExpanded, ref utilsShownVal);
            utilsShown[fieldEntry.Key] = utilsShownVal;
            var foldoutRect = GUILayoutUtility.GetLastRect();

            if (!propDisabled && UTEditorArray.HandleDragAndDrop(foldoutRect, serializedObject, propsList))
            {
                droppedObjects = true;
                if (listViewFields[0].onValueChaged == null)
                {
                    return;
                }

                HandleFieldChangeArray(listViewFields[0], parentProp, parentProp.arraySize - 1);
                return;
            }

            if (droppedObjects)
            {
                return;
            }
            if (!parentProp.isExpanded)
            {
                return;
            }
            EditorGUI.BeginDisabledGroup(propDisabled);
            // List View Utils
            if (utilsShownVal)
            {
                CreateListViewUtils(propsList, fieldEntry);
            }

            for (int i = 30 * page; i < Mathf.Min(parentProp.arraySize, 30 * (page + 1)); i++)
            {
                Rect   headerRect = default;
                Rect[] fieldRects = new Rect[listViewFields.Count];
                // get a react to draw a header later
                if (listViewFields.Count > 1 && i == 30 * page)
                {
                    headerRect = EditorGUILayout.GetControlRect();
                }

                EditorGUILayout.BeginHorizontal();

                // position controls
                if (UTEditorArray.RenderPositionControls(i, propsList, out var newIndex))
                {
                    HandleFieldChangeArray(listViewFields[0], parentProp.GetArrayElementAtIndex(newIndex), newIndex);
                    break;
                }

                var fieldIndex = 0;
                foreach (var field in listViewFields)
                {
                    var prop = serializedObject.FindProperty(field.name);

                    if (prop.arraySize != parentProp.arraySize)
                    {
                        prop.arraySize = parentProp.arraySize;
                    }

                    DrawFieldElement(field, prop.GetArrayElementAtIndex(i));
                    // saved the field width to reuse in the header later
                    if (listViewFields.Count > 1 && i == 30 * page)
                    {
                        fieldRects[fieldIndex] = GUILayoutUtility.GetLastRect();
                    }

                    fieldIndex++;
                }

                // removal controls
                if (UTEditorArray.RenderRemoveControls(i, propsList))
                {
                    if (listViewFields[0].onValueChaged != null)
                    {
                        HandleFieldChangeArray(listViewFields[0], null, i);
                    }

                    break;
                }

                EditorGUILayout.EndHorizontal();
                // draw a header with saved field widths
                // we only draw a header for cases where there are multiple elements
                if (listViewFields.Count > 1 && i == 30 * page)
                {
                    GUI.Box(headerRect, "", new GUIStyle("helpBox"));
                    for (int j = 0; j < listViewFields.Count; j++)
                    {
                        var adjustedRect = fieldRects[j];
                        if (j == 0)
                        {
                            adjustedRect.xMin = headerRect.xMin + 2;
                        }

                        adjustedRect.yMin = headerRect.yMin;
                        adjustedRect.yMax = headerRect.yMax;
                        EditorGUI.LabelField(adjustedRect,
                                             listViewFields[j].listViewColumnName ??
                                             serializedObject.FindProperty(listViewFields[j].name).displayName);
                    }
                }
            }

            EditorGUI.EndDisabledGroup();

            if (pageCount > 1)
            {
                EditorGUILayout.BeginHorizontal();
                EditorGUI.BeginDisabledGroup(page != pageCount - 1);
            }

            if (GUILayout.Button(listViewFields[0].listViewAddTitle ?? "Add Element"))
            {
                var insertAt = parentProp.arraySize;
                if (listViewFields[0].listViewAddMethod != null)
                {
                    listViewFields[0].listViewAddMethod.Invoke(t, new object[] { serializedObject });
                }
                else
                {
                    foreach (var field in listViewFields)
                    {
                        var prop = serializedObject.FindProperty(field.name);
                        prop.InsertArrayElementAtIndex(insertAt);
                    }
                }

                if (listViewFields[0].onValueChaged != null)
                {
                    HandleFieldChangeArray(listViewFields[0], parentProp.GetArrayElementAtIndex(insertAt), insertAt);
                }
            }

            if (pageCount > 1)
            {
                EditorGUI.EndDisabledGroup();
                EditorGUI.BeginDisabledGroup(page <= 0);
                if (GUILayout.Button(UTStyles.ArrowL, UTStyles.MiniArrowLeft))
                {
                    listPaginations[fieldEntry.Key]--;
                }
                EditorGUI.EndDisabledGroup();

                EditorGUI.BeginDisabledGroup(page >= pageCount - 1);
                if (GUILayout.Button(UTStyles.ArrowR, UTStyles.MiniArrowRight))
                {
                    listPaginations[fieldEntry.Key]++;
                }
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndHorizontal();
            }

            foreach (var uiAttr in uiAttrs)
            {
                uiAttr.AfterGUI(parentProp);
            }
        }
        private void HandleFields(Dictionary <string, UTFieldType> fields)
        {
            foreach (var fieldEntry in fields)
            {
                if (droppedObjects)
                {
                    break;
                }
                switch (fieldEntry.Value)
                {
                case UTFieldType.Regular: {
                    var prop = serializedObject.FindProperty(fieldEntry.Key);
                    DrawField(fieldCache[fieldEntry.Key], prop);
                    break;
                }

                case UTFieldType.Tab: {
                    var tabNames      = tabs.Select(i => i.Key).ToArray();
                    var tabSaveTarget = fieldCache[tabs[tabNames[0]].Keys.ToArray()[0]].tabSaveTarget;
                    if (!String.IsNullOrEmpty(tabSaveTarget))
                    {
                        var targetProp = serializedObject.FindProperty(tabSaveTarget);
                        tabOpen = targetProp.intValue;
                        EditorGUI.BeginChangeCheck();
                        tabOpen = GUILayout.Toolbar(tabOpen, tabNames);
                        if (EditorGUI.EndChangeCheck())
                        {
                            targetProp.intValue = tabOpen;
                            if (fieldCache.ContainsKey(tabSaveTarget))
                            {
                                var fieldChange = fieldCache?[tabSaveTarget].onValueChaged;
                                if (fieldChange != null)
                                {
                                    fieldChange.Invoke(t, new object[] { targetProp });
                                }
                            }
                        }
                    }
                    else
                    {
                        tabOpen = GUILayout.Toolbar(tabOpen, tabNames);
                    }
                    HandleFields(tabs[tabNames[tabOpen]]);
                    break;
                }

                case UTFieldType.Foldout: {
                    var     foldout = foldouts[fieldEntry.Key].First();
                    UTField field;
                    switch (foldout.Value)
                    {
                    case UTFieldType.Horizontal: {
                        field = horizontalViews[foldout.Key].First();
                        break;
                    }

                    case UTFieldType.ListView: {
                        field = listViews[foldout.Key].First();
                        break;
                    }

                    default: {
                        field = fieldCache[foldout.Key];
                        break;
                    }
                    }
                    var parentProp  = serializedObject.FindProperty(field.name);
                    var foldoutName = field.foldoutName;
                    parentProp.isExpanded = UTStyles.FoldoutHeader(foldoutName, parentProp.isExpanded);
                    if (!parentProp.isExpanded)
                    {
                        break;
                    }
                    EditorGUILayout.BeginVertical(new GUIStyle("helpBox"));
                    HandleFields(foldouts[fieldEntry.Key]);
                    EditorGUILayout.EndVertical();
                    break;
                }

                case UTFieldType.ListView: {
                    var listViewFields = listViews[fieldEntry.Key];
                    HandleListView(listViewFields, fieldEntry);
                    break;
                }

                case UTFieldType.Horizontal: {
                    if (droppedObjects)
                    {
                        break;
                    }
                    var horizontalFields = horizontalViews[fieldEntry.Key];
                    List <SerializedProperty> propsList = new List <SerializedProperty>();
                    foreach (var field in horizontalFields)
                    {
                        propsList.Add(serializedObject.FindProperty(field.name));
                    }

                    var uiAttrs = horizontalFields[0].uiAttrs;

                    var isVisible = true;
                    foreach (var uiAttr in uiAttrs)
                    {
                        if (!uiAttr.GetVisible(propsList[0]))
                        {
                            isVisible = false;
                            break;
                        }
                    }

                    if (!isVisible)
                    {
                        break;
                    }

                    foreach (var uiAttr in uiAttrs)
                    {
                        uiAttr.BeforeGUI(propsList[0]);
                    }

                    var horizontalAttr =
                        horizontalFields[0].attributes.Find(i => i is HorizontalAttribute) as HorizontalAttribute;
                    if (horizontalAttr.showHeader)
                    {
                        // header frame and label for the group
                        var oldColor   = GUI.backgroundColor;
                        var headerRect = EditorGUILayout.GetControlRect();
                        GUI.backgroundColor = new Color(oldColor.r, oldColor.g, oldColor.b, 0.5f);
                        GUI.Box(headerRect, "", new GUIStyle("helpBox"));
                        GUI.backgroundColor = oldColor;
                        EditorGUI.LabelField(headerRect, fieldEntry.Key);
                    }

                    EditorGUILayout.BeginHorizontal();
                    for (int i = 0; i < propsList.Count; i++)
                    {
                        DrawFieldElement(horizontalFields[i], propsList[i]);
                    }

                    EditorGUILayout.EndHorizontal();

                    foreach (var uiAttr in uiAttrs)
                    {
                        uiAttr.AfterGUI(propsList[0]);
                    }

                    break;
                }
                }
            }
        }