Customizing the Inspector

The inspector window shows the current selection’s properties, in our case called object fields. In the Inspector window there can be shown many types of object properties, starting from scene objects, assets, editor preferences, etc. If many different types are selected (for example some assets in the asset browser and some scene objects) the Inspector will show a list of those types and their count:

The editor.selection member is a table of type name and an array of (usually) numerical IDs for the selected type. As an example, if we selected few scene objects AND an asset in the asset browser, editor.selection will be made of:

editor.selection.object will be an id array like: {122,334,566,44} editor.selection.asset will be an id array like: {2,4,53,3442,3434,1566,244}

When editor.selection is {}, there is no selection in the editor.

Instances and Locking

The inspector can have many instances, created with editor.addInspectorInstance() or pushing the New Inspector button in the inspector window. Also one can lock the inspector to the current selection, and if the editor selection changes, this will not affect the locked inspector instances, they will keep showing their locked selection fields.

Selection Type Handlers

For the inspector to know what editing UI to show for the current editor selection, the user must call editor.registerInspectorTypeHandler(typeName, guiCallback) so that when it has a type having a non empty selection, it will call that specific guiCallback to draw the inspector window’s UI. By default there is already a handler registered for "object" which draws a field values editor for the selected scene objects.

If a user extension wants to render UI in the inspector for special selections, it will call the register function in the hook named onEditorInitialized which is called right after all extensions were loaded.

-- this is the guiCallback function which will be called to render inspector UI
local function assetInspectorGui(inspectorInfo)
  local selectedAssets
  -- if this inspector instance is not a locked one (not locked on a specific selection)
  -- then use the current editor selection
  if inspectorInfo.selection == nil then
    selectedAssets = editor.selection.asset
  else
  -- else use the locked selection from the given inspector info table
    selectedAssets = inspectorInfo.selection.asset
  end
  -- just show the list of selected assets
  for _, asset ipairs(selectedAssets) do
    ui_imgui.Text(asset)
  end
end

-- when the editor is initialized, this will be called after all extensions were loaded
local function onEditorInitialized()
  -- register out special selection type handler
  -- first is the name if our selection type
  -- second is the callback to be invoked when there is a valid editor.selection.asset array of selected assets
  editor.registerInspectorTypeHandler("asset", assetInspectorGui)
end

M.onEditorInitialized = onEditorInitialized
M.onExtensionLoaded = onExtensionLoaded
Inspector Header UI

If you want to show some specific tools/widgets depending on the current selection, you can add the onEditorInspectorHeaderGui to your extension’s M module. The function will receive an argument which is the inspectorInfo inspector instance info, having a selection member which is nil or the locked selection of that inspector instance. It will be called right after the call to render inspector widgets, basically any UI you emit in this function will be at the top of the Inspector window, independent of any inspector selection type. You can check the editor.selection to see if there is a type and an object of that type valid, so you can for example show some paint buttons for when a terrain is selected. If the current selection is of interest, just return from your function.

-- the function to show our terrain paint gui
local function showTerrainPaintGui(objectId)
  local obj = scenetree.findObjectById(objectId)
  -- if this object is a terrain block, then yes, show the terrain paint gui
  if obj:getClassName() == "TerrainBlock" then
    ui_imgui.Button("Raise height")
  end
end

-- called at the start of inspector window widget drawing
local function onEditorInspectorHeaderGui(inspectorInfo)
  -- if there is a locked selection in this inspector instance, use it
  if inspectorInfo.selection and #inspectorInfo.selection.object then
    showTerrainPaintGui(inspectorInfo.selection.object[1])
  -- if there is a current selection in this inspector instance, use it
  elseif editor.selection and #editor.selection.object then
    showTerrainPaintGui(editor.selection.object[1])
  end
end

-- make sure we're called by extensions.hook
M.onEditorInspectorHeaderGui = onEditorInspectorHeaderGui

There are various usages in the built-in editor tools, just look for onEditorInspectorHeaderGui occurences in the editor code to learn more.

Last modified: 22/4/2021 15:09

Any further questions?

Join our discord