//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
//**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************//
using System.Collections.Generic;
using System;
using System.Reflection;
using bs;
namespace bs.Editor
{
/** @addtogroup Inspector
* @{
*/
///
/// Displays GUI for a serializable property containing a generic object. Inspectable object fields are displayed
/// in separate rows.
///
public class InspectableObject : InspectableField
{
private const int IndentAmount = 5;
private object propertyValue;
private InspectorFieldDrawer drawer;
private InspectableFieldStyleInfo style;
private GUILayoutY guiLayout;
private GUILayoutX guiChildLayout;
private GUILayoutX guiTitleLayout;
private GUILayoutX guiInternalTitleLayout;
private GUIButton guiCreateBtn;
private ContextMenu createContextMenu;
private bool isExpanded;
private bool forceUpdate = true;
private bool isInline;
private State state;
private Type[] instantiableTypes;
///
/// Creates a new inspectable object GUI for the specified property.
///
/// Context shared by all inspectable fields created by the same parent.
/// 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).
/// 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 object whose contents to display.
/// Information that can be used for customizing field rendering and behaviour.
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();
});
}
}
}
}
///
public override GUILayoutX GetTitleLayout()
{
return guiTitleLayout;
}
///
public override InspectableState Refresh(int layoutIndex)
{
// Check if modified internally and rebuild if needed
object newPropertyValue = property.GetValue