/// <summary> /// Makes a deep copy of this object. /// </summary> public InspectableFieldStyleInfo Clone() { InspectableFieldStyleInfo style = new InspectableFieldStyleInfo(); style.StyleFlags = StyleFlags; if (RangeStyle != null) { style.RangeStyle = new InspectableFieldRangeStyle(RangeStyle.Min, RangeStyle.Max, RangeStyle.Slider); } if (StepStyle != null) { style.StepStyle = new InspectableFieldStepStyle(StepStyle.Step); } if (CategoryStyle != null) { style.CategoryStyle = new InspectableFieldCategoryStyle(CategoryStyle.Category); } if (OrderStyle != null) { style.OrderStyle = new InspectableFieldOrderStyle(OrderStyle.Index); } return(style); }
/// <summary> /// Creates a new field accessing the provided property. /// </summary> /// <param name="title">Title to display on the field.</param> /// <param name="name">Name of the field.</param> /// <param name="property">Property used to access the field contents.</param> /// <param name="style">Optional style used to customize the look of the field.</param> /// <param name="fieldCreateCallback"> /// Optional callback allowing the caller to override how is the field created. /// </param> private void AddFieldInternal(string title, string name, SerializableProperty property, InspectableFieldStyleInfo style, Func <string, InspectableFieldLayout, int, int, InspectableField> fieldCreateCallback) { int currentIndex; int childDepth; GUILayoutY parentLayout; if (category != null) { currentIndex = categoryIndex; parentLayout = category.ChildLayout; childDepth = depth + 1; } else { currentIndex = rootIndex; parentLayout = layout; childDepth = depth; } string childPath = string.IsNullOrEmpty(path) ? name : $"{path}/{name}"; InspectableField inspectableField = null; if (fieldCreateCallback != null) { inspectableField = fieldCreateCallback(path, new InspectableFieldLayout(parentLayout), currentIndex, depth); } if (inspectableField == null) { inspectableField = InspectableField.CreateField(context, title, childPath, currentIndex, childDepth, new InspectableFieldLayout(parentLayout), property, style); } if (category != null) { category.AddChild(inspectableField); } else { Fields.Add(inspectableField); } currentIndex += inspectableField.GetNumLayoutElements(); if (category != null) { categoryIndex = currentIndex; } else { rootIndex = currentIndex; } }
/// <summary> /// Creates all the relevant style information for a SerializableField. /// </summary> /// <param name="field">Field to create the style info structure for.</param> /// <returns>Style information retrieved from the field.</returns> public static InspectableFieldStyleInfo Create(SerializableField field) { SerializableFieldStyle style = field.Style; SerializableFieldAttributes flags = field.Flags; var styleInfo = new InspectableFieldStyleInfo(); styleInfo.RangeStyle = flags.HasFlag(SerializableFieldAttributes.Ranged) ? new InspectableFieldRangeStyle(style.RangeMin, style.RangeMax, style.DisplayAsSlider) : null; styleInfo.StepStyle = flags.HasFlag(SerializableFieldAttributes.Stepped) ? new InspectableFieldStepStyle(style.StepIncrement) : null; styleInfo.CategoryStyle = flags.HasFlag(SerializableFieldAttributes.Category) ? new InspectableFieldCategoryStyle(style.CategoryName) : null; styleInfo.OrderStyle = flags.HasFlag(SerializableFieldAttributes.Order) ? new InspectableFieldOrderStyle(style.Order) : null; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.AsLayerMask) ? InspectableFieldStyleFlags.AsLayerMask : 0; styleInfo.StyleFlags |= style.DisplayAsSlider ? InspectableFieldStyleFlags.AsSlider : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.PassByCopy) ? InspectableFieldStyleFlags.CopiedAsValue : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.NotNull) ? InspectableFieldStyleFlags.NotNull : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.NativeWrapper) ? InspectableFieldStyleFlags.NativeWrapper : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.ApplyOnDirty) ? InspectableFieldStyleFlags.ApplyOnDirty : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.AsQuaternion) ? InspectableFieldStyleFlags.AsQuaternion : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.Inline) ? InspectableFieldStyleFlags.Inline : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.LoadOnAssign) ? InspectableFieldStyleFlags.LoadOnAssign : 0; styleInfo.StyleFlags |= flags.HasFlag(SerializableFieldAttributes.HDR) ? InspectableFieldStyleFlags.HDR : 0; return(styleInfo); }
/// <summary> /// Creates a new inspectable object GUI for the specified property. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the object whose contents to display.</param> /// <param name="style">Information that can be used for customizing field rendering and behaviour.</param> public InspectableObject(InspectableContext context, string title, string path, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(context, title, path, SerializableProperty.FieldType.Object, depth, layout, property) { this.style = style; isExpanded = context.Persistent.GetBool(path + "_Expanded"); isInline = style != null && style.StyleFlags.HasFlag(InspectableFieldStyleFlags.Inline); // Builds a context menu that lets the user create objects to assign to this field. bool hasCreateButton = !property.IsValueType && !isInline; if (hasCreateButton) { instantiableTypes = GetInstantiableTypes(property.InternalType); if (instantiableTypes.Length > 1) { createContextMenu = new ContextMenu(); Array.Sort(instantiableTypes, (x, y) => string.Compare(x.Name, y.Name, StringComparison.Ordinal)); bool showNamespace = false; string ns = instantiableTypes[0].Namespace; for (int i = 1; i < instantiableTypes.Length; i++) { if (instantiableTypes[i].Namespace != ns) { showNamespace = true; break; } } foreach (var type in instantiableTypes) { string prefix = ""; if (showNamespace) { prefix = type.Namespace + "."; } createContextMenu.AddItem(prefix + type.Name, () => { StartUndo(); property.SetValue(Activator.CreateInstance(type)); EndUndo(); }); } } } }
/// <summary> /// Constructs a new inspectable array GUI. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Label to display on the list GUI title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties). /// </param> /// <param name="property">Serializable property referencing a single-dimensional array.</param> /// <param name="layout">Layout to which to append the list GUI elements to.</param> /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple /// nested containers whose backgrounds are overlaping. Also determines background style, /// depths divisible by two will use an alternate style.</param> /// <param name="style">Information that can be used for customizing field rendering and behaviour.</param> public InspectableArrayGUI(InspectableContext context, LocString title, string path, SerializableProperty property, GUILayout layout, int depth, InspectableFieldStyleInfo style) : base(title, layout, depth) { this.property = property; this.context = context; this.path = path; this.style = style; array = property.GetValue <Array>(); if (array != null) { numElements = array.Length; } }
/// <inheritdoc/> protected override GUILayoutX CreateGUI(GUILayoutY layout) { InspectableArrayGUI arrayParent = (InspectableArrayGUI)parent; SerializableProperty property = GetValue <SerializableProperty>(); InspectableFieldStyleInfo styleInfo = arrayParent.Style.Clone(); styleInfo.StyleFlags &= ~InspectableFieldStyleFlags.NativeWrapper; string entryPath = arrayParent.Path + "[" + SeqIndex + "]"; Field = CreateField(arrayParent.Context, SeqIndex + ".", entryPath, 0, Depth + 1, new InspectableFieldLayout(layout), property, styleInfo); return(Field.GetTitleLayout()); }
/// <summary> /// Creates a new inspectable ranged field GUI for the specified property. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="type">Type of property this field will be used for displaying.</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the field whose contents to display.</param> /// <param name="style">Contains information about the field style</param> public InspectableRangedField(InspectableContext context, string title, string path, SerializableProperty.FieldType type, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(context, title, path, type, depth, layout, property) { this.style = style; }
/// <summary> /// Creates a new inspectable color GUI for the specified property. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the field whose contents to display.</param> /// <param name="style">Contains information about the field style.</param> public InspectableColor(InspectableContext context, string title, string path, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(context, title, path, SerializableProperty.FieldType.Color, depth, layout, property) { hdr = style?.StyleFlags.HasFlag(InspectableFieldStyleFlags.HDR) ?? false; }
/// <summary> /// Creates a new inspectable AABox GUI for the specified property. /// </summary> /// <param name="parent">Parent Inspector this field belongs to.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the field whose contents to display.</param> /// <param name="style">Information that can be used for customizing field rendering and behaviour.</param> public InspectableAABox(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(parent, title, path, SerializableProperty.FieldType.Object, depth, layout, property) { }
/// <summary> /// Creates a new inspectable field, automatically detecting the most appropriate implementation for the type /// contained in the provided serializable property. This may be one of the built-in inspectable field implemetations /// (like ones for primitives like int or bool), or a user defined implementation defined with a /// <see cref="CustomInspector"/> attribute. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="layoutIndex">Index into the parent layout at which to insert the GUI elements for the field .</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the array whose contents to display.</param> /// <param name="style">Information that can be used for customizing field rendering and behaviour.</param> /// <returns>Inspectable field implementation that can be used for displaying the GUI for a serializable property /// of the provided type.</returns> public static InspectableField CreateField(InspectableContext context, string title, string path, int layoutIndex, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style = null) { InspectableField field = null; Type type = property.InternalType; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(RRef <>)) { type = type.GenericTypeArguments[0]; } Type customInspectable = InspectorUtility.GetCustomInspectable(type); if (customInspectable != null) { field = (InspectableField)Activator.CreateInstance(customInspectable, context, title, path, depth, layout, property, style); } else { switch (property.Type) { case SerializableProperty.FieldType.Int: if (style != null && style.StyleFlags.HasFlag(InspectableFieldStyleFlags.AsLayerMask)) { field = new InspectableLayerMask(context, title, path, depth, layout, property); } else { if (style?.RangeStyle == null || !style.RangeStyle.Slider) { field = new InspectableInt(context, title, path, depth, layout, property, style); } else { field = new InspectableRangedInt(context, title, path, depth, layout, property, style); } } break; case SerializableProperty.FieldType.Float: if (style?.RangeStyle == null || !style.RangeStyle.Slider) { field = new InspectableFloat(context, title, path, depth, layout, property, style); } else { field = new InspectableRangedFloat(context, title, path, depth, layout, property, style); } break; case SerializableProperty.FieldType.Bool: field = new InspectableBool(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Color: field = new InspectableColor(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.ColorGradient: field = new InspectableColorGradient(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Curve: field = new InspectableCurve(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.FloatDistribution: field = new InspectableFloatDistribution(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector2Distribution: field = new InspectableVector2Distribution(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector3Distribution: field = new InspectableVector3Distribution(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.ColorDistribution: field = new InspectableColorDistribution(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.String: field = new InspectableString(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector2: field = new InspectableVector2(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector3: field = new InspectableVector3(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector4: field = new InspectableVector4(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Quaternion: if (style != null && style.StyleFlags.HasFlag(InspectableFieldStyleFlags.AsQuaternion)) { field = new InspectableQuaternion(context, title, path, depth, layout, property); } else { field = new InspectableEuler(context, title, path, depth, layout, property); } break; case SerializableProperty.FieldType.Resource: field = new InspectableResource(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.RRef: field = new InspectableRRef(context, title, path, depth, layout, property, style); break; case SerializableProperty.FieldType.GameObjectRef: field = new InspectableGameObjectRef(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Object: field = new InspectableObject(context, title, path, depth, layout, property, style); break; case SerializableProperty.FieldType.Array: field = new InspectableArray(context, title, path, depth, layout, property, style); break; case SerializableProperty.FieldType.List: field = new InspectableList(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Dictionary: field = new InspectableDictionary(context, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Enum: field = new InspectableEnum(context, title, path, depth, layout, property); break; } } if (field == null) { throw new Exception("No inspector exists for the provided field type."); } field.Initialize(layoutIndex); field.Refresh(layoutIndex); return(field); }
/// <summary> /// Creates a new inspectable array GUI object that displays the contents of the provided serializable property. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Label to display on the list GUI title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties). /// </param> /// <param name="property">Serializable property referencing a single-dimensional array.</param> /// <param name="layout">Layout to which to append the list GUI elements to.</param> /// <param name="depth">Determines at which depth to render the background. Useful when you have multiple /// nested containers whose backgrounds are overlaping. Also determines background style, /// depths divisible by two will use an alternate style.</param> /// <param name="style">Information that can be used for customizing field rendering and behaviour.</param> public static InspectableArrayGUI Create(InspectableContext context, LocString title, string path, SerializableProperty property, GUILayout layout, int depth, InspectableFieldStyleInfo style) { InspectableArrayGUI guiArray = new InspectableArrayGUI(context, title, path, property, layout, depth, style); guiArray.BuildGUI(); return(guiArray); }
/// <summary> /// Creates a new inspectable float GUI for the specified property. /// </summary> /// <param name="parent">Parent Inspector this field belongs to.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the field whose contents to display.</param> /// <param name="style">Information that can be used for customizing field rendering and behaviour.</param> public InspectableFloat(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(parent, title, path, SerializableProperty.FieldType.Float, depth, layout, property) { this.style = style; }
/// <summary> /// Creates a new inspectable float GUI for the specified property with a range. /// </summary> /// <param name="context">Context shared by all inspectable fields created by the same parent.</param> /// <param name="title">Name of the property, or some other value to set as the title.</param> /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param> /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may /// contain other fields, in which case you should increase this value by one.</param> /// <param name="layout">Parent layout that all the field elements will be added to.</param> /// <param name="property">Serializable property referencing the field whose contents to display.</param> /// <param name="style">Information about the range of the field.</param> public InspectableRangedInt(InspectableContext context, string title, string path, int depth, InspectableFieldLayout layout, SerializableProperty property, InspectableFieldStyleInfo style) : base(context, title, path, SerializableProperty.FieldType.Int, depth, layout, property, style) { }