//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// using System; using BansheeEngine; namespace BansheeEditor { /** @addtogroup Inspector * @{ */ /// /// Inspectable field displays GUI elements for a single . This is a base class that /// should be specialized for all supported types contained by . Inspectable fields /// can and should be created recursively - normally complex types like objects and arrays will contain fields of their /// own, while primitive types like integer or boolean will consist of only a GUI element. /// public abstract class InspectableField { protected Inspector parent; protected InspectableFieldLayout layout; protected SerializableProperty property; protected string title; protected string path; protected int depth; protected SerializableProperty.FieldType type; /// /// Property this field is displaying contents of. /// public SerializableProperty Property { get { return property; } set { if (value == null) throw new ArgumentException("Cannot assign a null property to an inspectable field."); if (value.Type != type) { throw new ArgumentException( "Attempting to initialize an inspectable field with a property of invalid type."); } property = value; } } /// /// Creates a new inspectable field GUI for the specified property. /// /// Parent Inspector this field belongs to. /// Name of the property, or some other value to set as the title. /// Full path to this property (includes name of this property and all parent properties). /// Type of property this field will be used for displaying. /// 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. /// Parent layout that all the field elements will be added to. /// Serializable property referencing the array whose contents to display. public InspectableField(Inspector parent, string title, string path, SerializableProperty.FieldType type, int depth, InspectableFieldLayout layout, SerializableProperty property) { this.parent = parent; this.layout = layout; this.title = title; this.path = path; this.type = type; this.depth = depth; Property = property; } /// /// Checks if contents of the field have been modified, and updates them if needed. /// /// Index in the parent's layout at which to insert the GUI elements for this field. /// /// State representing was anything modified between two last calls to . public virtual InspectableState Refresh(int layoutIndex) { return InspectableState.NotModified; } /// /// Returns the total number of GUI elements in the field's layout. /// /// Number of GUI elements in the field's layout. public int GetNumLayoutElements() { return layout.NumElements; } /// /// Returns an optional title layout. Certain fields may contain separate title and content layouts. Parent fields /// may use the separate title layout instead of the content layout to append elements. Having a separate title /// layout is purely cosmetical. /// /// Title layout if the field has one, null otherwise. public virtual GUILayoutX GetTitleLayout() { return null; } /// /// Initializes the GUI elements for the field. /// /// Index at which to insert the GUI elements. protected internal abstract void Initialize(int layoutIndex); /// /// Destroys all GUI elements in the inspectable field. /// public virtual void Destroy() { layout.DestroyElements(); } /// /// 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 /// attribute. /// /// Parent Inspector this field belongs to. /// Name of the property, or some other value to set as the title. /// Full path to this property (includes name of this property and all parent properties). /// Index into the parent layout at which to insert the GUI elements for the field . /// 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. /// Parent layout that all the field elements will be added to. /// Serializable property referencing the array whose contents to display. /// Information related the field style /// Inspectable field implementation that can be used for displaying the GUI for a serializable property /// of the provided type. public static InspectableField CreateInspectable(Inspector parent, 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, depth, title, property); } else { switch (property.Type) { case SerializableProperty.FieldType.Int: if (style?.RangeStyle == null || !style.RangeStyle.Slider) { field = new InspectableInt(parent, title, path, depth, layout, property, style); } else { field = new InspectableRangedInt(parent, title, path, depth, layout, property, style); } break; case SerializableProperty.FieldType.Float: if (style?.RangeStyle == null || !style.RangeStyle.Slider) { field = new InspectableFloat(parent, title, path, depth, layout, property, style); } else { field = new InspectableRangedFloat(parent, title, path, depth, layout, property, style); } break; case SerializableProperty.FieldType.Bool: field = new InspectableBool(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Color: field = new InspectableColor(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.ColorGradient: field = new InspectableColorGradient(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Curve: field = new InspectableCurve(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.FloatDistribution: field = new InspectableFloatDistribution(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.ColorDistribution: field = new InspectableColorDistribution(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.String: field = new InspectableString(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector2: field = new InspectableVector2(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector3: field = new InspectableVector3(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Vector4: field = new InspectableVector4(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Resource: field = new InspectableResource(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.RRef: field = new InspectableRRef(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.GameObjectRef: field = new InspectableGameObjectRef(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Object: field = new InspectableObject(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Array: field = new InspectableArray(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.List: field = new InspectableList(parent, title, path, depth, layout, property); break; case SerializableProperty.FieldType.Dictionary: field = new InspectableDictionary(parent, 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; } } /** @} */ }