Game.UI.Widgets.EditorGenerator
Assembly: Game
Namespace: Game.UI.Widgets
Type: public class EditorGenerator
Base: IEditorGenerator
Summary:
EditorGenerator is the central factory that produces editor UI widgets for object graphs (fields, lists, and nested objects) used by the in-game editor/inspector. It:
- Uses a set of IFieldBuilderFactory implementations (kFactories) to create field widgets for primitive and common types.
- Builds list adapters (ArrayAdapter / ListAdapter) for list/array types.
- Builds expandable groups for serializable complex types (excluding ComponentBase).
- Applies a custom member filter (kMemberFilter) to determine which fields are exposed.
- Handles display name and tooltip localization by reading attributes (InspectorNameAttribute, EditorNameAttribute, TooltipAttribute) and generating locale ids.
- Protects against excessive recursion via maxLevel and supports a global bypass flag sBypassValueLimits used by field builders.
Fields
-
public static readonly List<IFieldBuilderFactory> kFactories
A predefined ordered list of factories used to create FieldBuilder delegates for many common types (custom, toggle, int, uint, time, float, bounds, bezier, string, color, animation curve, enum, popup-value). Factories are tried in order by TryCreateFieldBuilder to match a field type with a builder. -
private static readonly CustomSerializationPolicy kMemberFilter
A CustomSerializationPolicy that controls which members are considered serializable/exposed to the editor. It allows non-serializable types, requires fields to be public, and filters out fields marked [NonSerialized], [HideInInspector], [HideInEditorAttribute], or fields named "active", "dirty", "m_Dirty". Also excludes the "components" field on PrefabBase-derived types. Used by BuildMembers to query members via FormatterUtilities.GetSerializableMembers.
Properties
-
public int maxLevel { get; set; }
Default: 5. Maximum recursion depth for generating nested editors. If the current level exceeds maxLevel, Build returns a simple ValueField with an empty string accessor to avoid deep recursion and stack overflows / extremely large editors. -
public static bool sBypassValueLimits { get; set; }
Static flag that field builders can read to bypass value limits (used by some numeric or constrained fields). Acts as a global override for value constraints in UI builders.
Constructors
public EditorGenerator()
Implicit default constructor. Initializes an EditorGenerator instance that will use the static kFactories and kMemberFilter to create widgets. No special construction logic is defined in the source file (default behavior).
Methods
-
public IWidget Build(IValueAccessor accessor, object[] attributes, int level, string path)
Entry point to generate an IWidget for the given accessor. If level > maxLevel it returns a fallback ValueField; otherwise it delegates to BuildMemberImpl to attempt to create a field, list, or group representation. -
private IWidget TryBuildField(IValueAccessor accessor, object[] attributes, string path)
Attempts to build a field widget by creating a FieldBuilder for accessor.valueType (via TryCreateFieldBuilder). If successful, invokes the FieldBuilder to create the widget, sets widget.path, and returns it; otherwise returns null. -
private FieldBuilder TryCreateFieldBuilder(Type memberType, object[] attributes)
Iterates through kFactories calling TryCreate on each to find an appropriate FieldBuilder for the given memberType and attributes. Returns the first matching FieldBuilder or null if none match. -
public PagedList TryBuildList(IValueAccessor accessor, int level, string path, object[] attributes)
Attempts to build a PagedList by creating an IListAdapter (via TryBuildListAdapter). If a list adapter is returned, wraps it in a PagedList configured with adapter, level, and path; otherwise returns null. -
public IListAdapter TryBuildListAdapter(IValueAccessor accessor, int level, string path, object[] attributes)
If accessor.valueType is a list/array type, determines the element type and label member. Creates: - an ArrayAdapter for arrays (accessor cast to Array),
-
or a ListAdapter for IList types (accessor cast to IList), populating adapter properties: elementType, generator (this), level, path, resizable based on FixedLengthAttribute presence, attributes, and labelMember. Returns null if not a supported list type.
-
private ExpandableGroup TryBuildGroup(IValueAccessor accessor, int level, string path)
Builds an ExpandableGroup for complex serializable types (accessor.valueType.IsSerializable) that are not ComponentBase derived. The group's children are generated by BuildMembers(accessor, level, path). Returns null if not applicable. -
public IEnumerable<IWidget> BuildMembers(IValueAccessor accessor, int level, string parentPath)
Generates widgets for members of the accessed object. It first collects "special" members (GetSpecialMembers) and then uses FormatterUtilities.GetSerializableMembers with kMemberFilter to get remaining members. Returns a sequence of IWidget created by BuildMember for each member. -
private MemberInfo[] GetSpecialMembers(Type type)
Provides type-specific special members. For types inheriting from PrefabBase it exposes the UnityEngine.Object "name" property. Otherwise returns an empty array. This ensures prefab name is editable/visible in editors. -
public static T NamedWidget<T>(T widget, LocalizedString displayName, LocalizedString tooltip) where T : IWidget
Utility that, if the widget implements INamed, sets its displayName; if it implements ITooltipTarget, sets its tooltip. Returns the same widget instance for chaining. -
private IWidget BuildMember(IValueAccessor parent, MemberInfo member, int level, string parentPath)
Creates a member accessor (ValueAccessorUtils.CreateMemberAccessor) and builds the widget via BuildMemberImpl. If the resulting widget supports INamed or ITooltipTarget, it sets the displayName (from EditorNameAttribute / InspectorNameAttribute / nicified member name) and tooltip (from TooltipAttribute or computed locale id). Returns the configured widget. -
private IWidget BuildMemberImpl(IValueAccessor accessor, object[] attributes, int level, string path)
Core decision method: tries to build a field (TryBuildField), then a list (TryBuildList), then a group (TryBuildGroup). If none succeed, returns a ValueField created by BuildUnknownMember to display the member type name. -
private ValueField BuildUnknownMember(Type memberType)
Creates a simple ValueField that shows memberType.Name via an ObjectAccessor. Used as a fallback for unsupported/unknown member types. -
private static string GetMemberTooltipLocaleId(MemberInfo member)
Generates a locale id for a member tooltip using the member's declaring type full name (if available) and member name, in the format "Editor.TOOLTIP[FullTypeName.MemberName]" (or "Editor.TOOLTIP[MemberName]" if declaring type absent).
Usage Example
// Create a generator and produce a widget for an object instance.
// Assume MySerializable is a serializable class and myInstance is an instance.
var generator = new EditorGenerator();
var accessor = new ObjectAccessor<MySerializable>(myInstance);
// Build a widget tree rooted at "root" at level 0 with no extra attributes.
IWidget rootWidget = generator.Build(accessor, new object[0], 0, "root");
// rootWidget can then be used by the UI system (added to an inspector panel, etc.)
Notes: - EditorGenerator relies on many framework types (IValueAccessor, IWidget, FieldBuilder, ArrayAdapter, ListAdapter, ValueField, PagedList, ExpandableGroup, FormatterUtilities, WidgetReflectionUtils) from the game's UI/editor and serialization utility layers. - To extend supported field types add factories to kFactories (or register new IFieldBuilderFactory implementations).