Beispiel #1
0
        public static object DecimalDrawer(object obj, InvokeWrapper wrapper, GUISkin skin)
        {
            float value = wrapper.GetContainingType() == typeof(double) ?
                          Convert.ToSingle(wrapper.Get <double>(obj)) :
                          wrapper.Get <float>(obj);
            FloatSliderInInspector slider = wrapper.GetAttribute <FloatSliderInInspector>();

            if (slider != null)
            {
                return(EditorGUILayout.Slider(MakeLabel(wrapper.Member), value, slider.Min, slider.Max));
            }
            else
            {
                return(EditorGUILayout.FloatField(MakeLabel(wrapper.Member), value, skin.textField));
            }
        }
Beispiel #2
0
        public void Update(InvokeWrapper wrapper, object targetInstance)
        {
            var foldoutBeginAttribute = wrapper.GetAttribute <InspectorGroupBeginAttribute>();

            if (foldoutBeginAttribute != null || wrapper.HasAttribute <InspectorGroupEndAttribute>())
            {
                End();
            }

            if (foldoutBeginAttribute == null)
            {
                return;
            }

            var groupIdentifier = (targetInstance != null ? targetInstance.GetType().FullName : "null") +
                                  "_" + foldoutBeginAttribute.Name;

            Begin(!InspectorGUI.Foldout(EditorData.Instance.GetData(targetInstance as Object,
                                                                    groupIdentifier),
                                        GUI.MakeLabel(foldoutBeginAttribute.Name)));
        }
Beispiel #3
0
        private static DefaultAndUserValueResult HandleDefaultAndUserValue <ValueT>(object[] objects,
                                                                                    InvokeWrapper wrapper)
            where ValueT : struct
        {
            if (s_floatFieldMethod == null)
            {
                s_floatFieldMethod = typeof(EditorGUI).GetMethod("FloatField",
                                                                 new[]
                {
                    typeof(Rect),
                    typeof(string),
                    typeof(float)
                });
            }
            if (s_vector3FieldMethod == null)
            {
                s_vector3FieldMethod = typeof(EditorGUI).GetMethod("Vector3Field",
                                                                   new[]
                {
                    typeof(Rect),
                    typeof(string),
                    typeof(Vector3)
                });
            }

            var method = typeof(ValueT) == typeof(float) ?
                         s_floatFieldMethod :
                         typeof(ValueT) == typeof(Vector3) ?
                         s_vector3FieldMethod :
                         null;

            if (method == null)
            {
                throw new NullReferenceException("Unknown DefaultAndUserValue type: " + typeof(ValueT).Name);
            }

            var updateButtonWidth = 20.0f;
            var rect = EditorGUILayout.GetControlRect();

            // Now we know the total width if the Inspector. Remove
            // width of button and right most spacing.
            rect.xMax -= updateButtonWidth;

            // We don't want the tooltip of the toggle to show when
            // hovering the update button or float field(s) so use
            // xMax as label width minus some magic number so that
            // e.g., Mass float field slider appears and works.
            var widthUntilButton = rect.xMax;

            rect.xMax = EditorGUIUtility.labelWidth - 28;

            // Result and reference instance.
            var result   = new DefaultAndUserValueResult();
            var instance = wrapper.Get <DefaultAndUserValue <ValueT> >(objects[0]);

            UnityEngine.GUI.changed = false;
            var hasMixedUseDefault = !CompareMulti <ValueT>(objects,
                                                            wrapper,
                                                            other => other.UseDefault == instance.UseDefault);

            EditorGUI.showMixedValue = hasMixedUseDefault;

            var toggleInput = hasMixedUseDefault ?
                              false :
                              instance.UseDefault;
            // During showMixedValue - Toggle will always return true (enabled)
            // when the user clicks regardless of instance.UseDefault.
            var toggleOutput = EditorGUI.ToggleLeft(rect,
                                                    GUI.MakeLabel(wrapper.Member.Name.SplitCamelCase(),
                                                                  false,
                                                                  "If checked - value will be default. Uncheck to manually enter value."),
                                                    toggleInput);

            if (toggleOutput != toggleInput)
            {
                result.DefaultToggleChanged = true;
                result.UseDefault           = toggleOutput;
            }

            // Restore width and calculate new start of the float
            // field(s). Start is label width but we have to remove
            // the current indent level since label width is independent
            // of the indent level. Unsure why we have to add LayoutMagicNumber pixels...
            // could be float field(s) default minimum label size.
            rect.xMax  = widthUntilButton;
            rect.x     = EditorGUIUtility.labelWidth - InspectorGUI.IndentScope.PixelLevel + InspectorGUI.LayoutMagicNumber;
            rect.xMax += -rect.x + InspectorGUI.LayoutMagicNumber;

            s_fieldMethodArgs[0] = rect;
            s_fieldMethodArgs[2] = instance.Value;
            var newValue = default(ValueT);

            EditorGUI.showMixedValue = !CompareMulti <ValueT>(objects,
                                                              wrapper,
                                                              other => instance.Value.Equals(other.Value));
            using (new GUI.EnabledBlock(!instance.UseDefault && !hasMixedUseDefault)) {
                EditorGUI.BeginChangeCheck();
                newValue = (ValueT)method.Invoke(null, s_fieldMethodArgs);
                if (EditorGUI.EndChangeCheck())
                {
                    // Validate input here so that, e.g., 0 isn't propagated. It's
                    // not possible to check this in the CopyOp callback.
                    var clampAttribute = wrapper.GetAttribute <ClampAboveZeroInInspector>();
                    if (clampAttribute == null || clampAttribute.IsValid(newValue))
                    {
                        result.OnChange <ValueT>(instance.Value, newValue);
                    }
                }
            }

            rect.x      = rect.xMax;
            rect.width  = updateButtonWidth;
            rect.height = EditorGUIUtility.singleLineHeight -
                          EditorGUIUtility.standardVerticalSpacing;
            result.UpdateDefaultClicked = InspectorGUI.Button(rect,
                                                              MiscIcon.Update,
                                                              instance.UseDefault,
                                                              InspectorEditor.Skin.ButtonRight,
                                                              "Force update of default value.",
                                                              1.2f);

            return(result);
        }
Beispiel #4
0
        public static bool HandleType(InvokeWrapper wrapper, T target, GUISkin skin)
        {
            object value      = null;
            bool   isNullable = false;
            Type   type       = wrapper.GetContainingType();

            if (type == typeof(Vector4) && wrapper.CanRead())
            {
                Vector4 valInField = wrapper.Get <Vector4>();
                value = EditorGUILayout.Vector4Field(MakeLabel(wrapper.Member).text, valInField);
            }
            else if (type == typeof(Vector3) && wrapper.CanRead())
            {
                Vector3 valInField = wrapper.Get <Vector3>();
                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label(MakeLabel(wrapper.Member));
                    value = EditorGUILayout.Vector3Field("", valInField);
                }
                GUILayout.EndHorizontal();
            }
            else if (type == typeof(Vector2) && wrapper.CanRead())
            {
                Vector2 valInField = wrapper.Get <Vector2>();
                value = EditorGUILayout.Vector2Field(MakeLabel(wrapper.Member).text, valInField);
            }
            else if ((type == typeof(float) || type == typeof(double)) && wrapper.CanRead())
            {
                float valInField = type == typeof(double) ? Convert.ToSingle(wrapper.Get <double>()) : wrapper.Get <float>();
                FloatSliderInInspector slider = wrapper.GetAttribute <FloatSliderInInspector>();
                if (slider != null)
                {
                    value = EditorGUILayout.Slider(MakeLabel(wrapper.Member), valInField, slider.Min, slider.Max);
                }
                else
                {
                    value = EditorGUILayout.FloatField(MakeLabel(wrapper.Member), valInField, skin.textField);

                    // I can't remember why I tested this approach.
                    //GUILayout.BeginHorizontal();
                    //{
                    //  GUILayout.Label( MakeLabel( wrapper.Member ) );
                    //  value = EditorGUILayout.FloatField( valInField, skin.textField );
                    //}
                    //GUILayout.EndHorizontal();
                }
            }
            else if (type == typeof(int) && wrapper.CanRead())
            {
                int valInField = wrapper.Get <int>();
                value = EditorGUILayout.IntField(MakeLabel(wrapper.Member), valInField, skin.textField);
            }
            else if (type == typeof(bool) && wrapper.CanRead())
            {
                bool valInField = wrapper.Get <bool>();
                value = Utils.GUI.Toggle(MakeLabel(wrapper.Member), valInField, skin.button, skin.label);
            }
            else if (type == typeof(Color) && wrapper.CanRead())
            {
                Color valInField = wrapper.Get <Color>();
                value = EditorGUILayout.ColorField(MakeLabel(wrapper.Member), valInField);
            }
            else if (type == typeof(DefaultAndUserValueFloat) && wrapper.CanRead())
            {
                DefaultAndUserValueFloat valInField = wrapper.Get <DefaultAndUserValueFloat>();

                float newValue = Utils.GUI.HandleDefaultAndUserValue(wrapper.Member.Name, valInField, skin);
                if (wrapper.IsValid(newValue))
                {
                    if (!valInField.UseDefault)
                    {
                        valInField.Value = newValue;
                    }
                    value = valInField;
                }
            }
            else if (type == typeof(DefaultAndUserValueVector3) && wrapper.CanRead())
            {
                DefaultAndUserValueVector3 valInField = wrapper.Get <DefaultAndUserValueVector3>();

                Vector3 newValue = Utils.GUI.HandleDefaultAndUserValue(wrapper.Member.Name, valInField, skin);
                if (wrapper.IsValid(newValue))
                {
                    if (!valInField.UseDefault)
                    {
                        valInField.Value = newValue;
                    }
                    value = valInField;
                }
            }
            else if (type == typeof(RangeReal))
            {
                RangeReal valInField = wrapper.Get <RangeReal>();

                GUILayout.BeginHorizontal();
                {
                    GUILayout.Label(MakeLabel(wrapper.Member), skin.label);
                    valInField.Min = EditorGUILayout.FloatField("", (float)valInField.Min, skin.textField, GUILayout.MaxWidth(64));
                    valInField.Max = EditorGUILayout.FloatField("", (float)valInField.Max, skin.textField, GUILayout.MaxWidth(64));
                }
                GUILayout.EndHorizontal();

                if (valInField.Min > valInField.Max)
                {
                    valInField.Min = valInField.Max;
                }

                value = valInField;
            }
            else if (type == typeof(string) && wrapper.CanRead())
            {
                value = EditorGUILayout.TextField(MakeLabel(wrapper.Member), wrapper.Get <string>(), skin.textField);
            }
            else if (type.IsEnum && type.IsVisible && wrapper.CanRead())
            {
                Enum valInField = wrapper.Get <System.Enum>();
                value = EditorGUILayout.EnumPopup(MakeLabel(wrapper.Member), valInField, skin.button);
            }
            else if (type.IsArray && wrapper.CanRead())
            {
                Array array = wrapper.Get <Array>();
                if (array.Length == 0)
                {
                    GUILayout.BeginHorizontal();
                    {
                        GUILayout.Label(MakeLabel(wrapper.Member), skin.label);
                        GUILayout.Label(Utils.GUI.MakeLabel("Empty array", true), skin.label);
                    }
                    GUILayout.EndHorizontal();
                }
                else
                {
                    Utils.GUI.Separator();
                    using (new Utils.GUI.Indent(12))
                        foreach (object obj in wrapper.Get <Array>())
                        {
                            DrawMembersGUI(obj, target, skin);
                        }
                    Utils.GUI.Separator();
                }
            }
            else if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List <>) && wrapper.CanRead())
            {
                HandleList(wrapper, target, skin);
            }
            else if (type == typeof(IFrame) && wrapper.CanRead())
            {
                IFrame frame = wrapper.Get <IFrame>();
                Utils.GUI.HandleFrame(frame, skin);
            }
            else if ((typeof(ScriptAsset).IsAssignableFrom(type) ||
                      type.BaseType == typeof(UnityEngine.Object) ||
                      type.BaseType == typeof(ScriptComponent)) && wrapper.CanRead())
            {
                bool allowSceneObject = type == typeof(GameObject) ||
                                        type.BaseType == typeof(ScriptComponent);
                UnityEngine.Object valInField = wrapper.Get <UnityEngine.Object>();
                bool recursiveEditing         = wrapper.HasAttribute <AllowRecursiveEditing>();
                bool createNewAssetButton     = false;

                if (recursiveEditing)
                {
                    var foldoutData = EditorData.Instance.GetData(target as UnityEngine.Object, wrapper.Member.Name);

                    GUILayout.BeginHorizontal();
                    {
                        var objFieldLabel = MakeLabel(wrapper.Member);
                        var buttonSize    = skin.label.CalcHeight(objFieldLabel, Screen.width);
                        UnityEngine.GUI.enabled = valInField != null;
                        foldoutData.Bool        = GUILayout.Button(Utils.GUI.MakeLabel(foldoutData.Bool ? "-" : "+"),
                                                                   skin.button,
                                                                   new GUILayoutOption[] { GUILayout.Width(20.0f), GUILayout.Height(buttonSize) }) ?
                                                  // Button clicked - toggle current value.
                                                  !foldoutData.Bool :
                                                  // If foldout were enabled but valInField has changed to null - foldout will become disabled.
                                                  valInField != null && foldoutData.Bool;
                        UnityEngine.GUI.enabled = true;
                        value = EditorGUILayout.ObjectField(objFieldLabel, valInField, type, allowSceneObject, new GUILayoutOption[] { });

                        if (typeof(ScriptAsset).IsAssignableFrom(type))
                        {
                            GUILayout.Space(4);
                            using (new GUI.ColorBlock(Color.Lerp(UnityEngine.GUI.color, Color.green, 0.1f)))
                                createNewAssetButton = GUILayout.Button(GUI.MakeLabel("New", false, "Create new asset"),
                                                                        GUILayout.Width(42),
                                                                        GUILayout.Height(buttonSize));
                        }
                    }
                    GUILayout.EndHorizontal();

                    if (GUILayoutUtility.GetLastRect().Contains(Event.current.mousePosition) && Event.current.type == EventType.MouseDown && Event.current.button == 0)
                    {
                        foldoutData.Bool = !foldoutData.Bool;
                        GUIUtility.ExitGUI();
                    }

                    if (foldoutData.Bool)
                    {
                        using (new Utils.GUI.Indent(12)) {
                            Utils.GUI.Separator();

                            GUILayout.Space(6);

                            GUILayout.Label(Utils.GUI.MakeLabel("Changes made to this object will affect all objects referencing this asset.",
                                                                Color.Lerp(Color.red, Color.white, 0.25f),
                                                                true),
                                            new GUIStyle(skin.textArea)
                            {
                                alignment = TextAnchor.MiddleCenter
                            });

                            GUILayout.Space(6);

                            // Executes OnInspectorGUI on a custom editor if it exist - otherwise Update.
                            Editor editor = null;
                            if (value is UnityEngine.Object && (editor = Editor.CreateEditor(value as UnityEngine.Object)) != null)
                            {
                                var updateMethod = typeof(BaseEditor <>).MakeGenericType(value.GetType()).GetMethod("OnRecursiveInspectorGUI", BindingFlags.Public | BindingFlags.Instance);
                                updateMethod.Invoke(editor, new object[] { target });
                            }
                            else
                            {
                                var updateMethod = typeof(BaseEditor <>).MakeGenericType(typeof(T)).GetMethod("Update", BindingFlags.Public | BindingFlags.Static);
                                updateMethod.Invoke(null, new object[] { value, target, skin });
                            }

                            Utils.GUI.Separator();
                        }
                    }
                }
                else
                {
                    value = EditorGUILayout.ObjectField(MakeLabel(wrapper.Member), valInField, type, allowSceneObject, new GUILayoutOption[] { });
                }

                if (createNewAssetButton)
                {
                    var assetName = type.Name.SplitCamelCase().ToLower();
                    var result    = EditorUtility.SaveFilePanel("Create new " + assetName, "Assets", "new " + assetName + ".asset", "asset");
                    if (result != string.Empty)
                    {
                        var info         = new System.IO.FileInfo(result);
                        var relativePath = IO.Utils.MakeRelative(result, Application.dataPath);
                        var newInstance  = ScriptAsset.Create(type);
                        newInstance.name = info.Name;
                        AssetDatabase.CreateAsset(newInstance, relativePath + (info.Extension == ".asset" ? "" : ".asset"));
                        AssetDatabase.SaveAssets();
                        AssetDatabase.Refresh();

                        value = newInstance;
                    }
                }

                isNullable = true;
            }
            else if (type.IsClass && wrapper.CanRead())
            {
            }

            return(UnityEngine.GUI.changed &&
                   (value != null || isNullable) &&
                   wrapper.ConditionalSet(value));
        }