06. Drawers For Components

  10. Extending Power Inspector No Comments

Extending A Base Class

If you want to create a new drawer for a component, you can derive from one of two base classes that implements the IComponentDrawer interface.

1. ComponentDrawer

Extend ComponentDrawer if an Editor is not used for drawing the class members of the Component.

This gives you the most power to customize the drawer, and should be used when possible for the best results.

Example: TransformDrawer

2. CustomEditorComponentDrawer

Extend CustomEditorComponentDrawer if an Editor is used for drawing the class members of the Component.

In this case your options for customizing the drawer will be more limited, but you can still do things like add new header buttons or customize the context menu.

This is mainly used when the target component has a Custom Editor.

Example: CameraDrawer

DrawerForComponent

For Power Inspector to know which Components should be represented by the drawer class you’ve created, you’ll need to add the DrawerForComponent attribute to the class.

Here is an example of the attribute being used:

/// <summary>
/// Handles drawing the Transform component inside the inspector view.
/// </summary>
[Serializable, DrawerForComponent(typeof(Transform))]
public class TransformDrawer : ComponentDrawer

Setup

When Power Inspector prepares a drawer for use inside an Inspector, it will call two methods inside the drawer class:

  1. First, it will call the SetupInterface method (defined in the IEditorlessComponentDrawer and ICustomEditorComponentDrawer interfaces).
  2. After that has finished, it will call the LateSetup method (defined in the base IDrawer interface).

All drawer class also contain a Setup method. The only job of the SetupInterface method is to take the parameters provided by Power Inspector, and to convert them into a form that the main Setup method can accept, and then call that Setup method.

You can override the Setup and LateSetup methods if you want to customize the setup phase.

IMPORTANT NOTE
If you override Setup or LateSetup, remember to always also call base.Setup and base.LateSetup!

DoGenerateMemberBuildList

You can override the DoGenerateMemberBuildList method to modify which class members of your component should be included inside the drawer.

You do this by adding LinkedMemberInfos for the fields, properties and methods that you want to be built into a list called memberBuildList.

LinkedMemberInfos are similar to the MemberInfo class in .NET, and are used internally by drawers in Power Inspector to get and set the values of class members of different types. In fact, they usually work by wrapping a MemberInfo internally and layering functionality on top of it.

You can use ParentDrawerUtility.GetMemberBuildList to generate the default member build list for your component, and then start editing it from there by adding or removing specific elements.

using System.Collections.Generic;
using Sisus;
using Sisus.Attributes;

[DrawerForComponent(typeof(MyComponent))]
public class MyComponentDrawer : ComponentDrawer
{
	/// <inheritdoc/>
	protected override void DoGenerateMemberBuildList()
	{
		// Get ALL class members for the component by setting includeHidden to true.
		// Returned members will include non-public members, non-serialized members, fields, properties and methods.
		var allClassMembers = new List<LinkedMemberInfo>();
		const bool includeHidden = true;
		ParentDrawerUtility.GetMemberBuildList(this, linkedMemberHierarchy, ref allClassMembers, includeHidden);
		
		// Add only the members you want shown to the member build list
		foreach(var linkedMember in allClassMembers)
		{
			switch(linkedMember.Name)
			{
				case "MyField":
				case "MyProperty":
				case "MyMethod":
					memberBuildList.Add(linkedMember);
					break;
			}
		}
	}
}

DoBuildMembers

You can also override DoBuildMembers to customize exactly what member drawers are built based on the memberBuildList that was previously generated by the DoGenerateMemberBuildList method.

During the execution of this method all member drawers should be created and placed into the members array. If you want to add any member drawers that are not backed by a field, property or method in the component, you can do so here.

You can use ParentDrawerUtility.BuildMembers to automatically generate members based on the contents of the memberBuildList, and this is what will happen if you do not override DoBuildMembers.

using UnityEngine;
using Sisus;
using Sisus.Attributes;

[DrawerForComponent(typeof(MyComponent))]
public class MyComponentDrawer : ComponentDrawer
{
	/// <inheritdoc/>
	protected override void DoBuildMembers()
	{
		// build default member drawers
		base.DoBuildMembers();

		// add a button member
		var button = ButtonDrawer.Create("My Button", OnMyButtonClicked, this);
		members = members.Add(button);
	}

	private void OnMyButtonClicked()
	{
		foreach(var target in targets)
		{
			Debug.Log("Clicked My Button on MyComponent target " + target.name);
		}
	}
}