Using tool menus for editor extension

This tutorial cover the use of toolmenus to create a toolbar button in the level viewport. This button when clicked open up a Editor utility widget wich you can use to make your own tool.

Updated over 4 years ago

Let's create a toolbar button that opens an Editor Widget. This button is created at the engine startup by using the Run function provided by EditorUtilityClasses. On click, the button runs a console command which calls a custom event. This event opens our Editor Widget.

Create a content plugin

First create a content plugin, this step is not required.

Creating a plugin is recommended for reuse of your tool.

On the Menubar select Edit then Plugin a window pop, click New plugin.

  • Finally select create plugin

Create the required Classes

Add a folder:

  • Right click the ContentBrowser

  • Select New Folder

  • Name it: "Tutorial"

Our Hook, our entry point

Right Click in the ContentBrowser then Select Editor Utility Blueprint like below

Then pick EditorUtilityObject

  • Call it BPU_TutoStartupHook

  • Right click on it and Copy Reference

Open Your project folder navigate to Config and edit DefaultEditorPerProjectUserSettings.ini and add:

[/Script/Blutility.EditorUtilitySubsystem]

StartupObjects="PasteYourReferenceHere"

Remove EditorUtilityBlueprint' from the pasted reference the final line should be like

StartupObjects="/MyToolTuto/Tutorial/BPU_TutoStartupHook.BPU_TutoStartupHook"

The widget

Create a Editor Utility Widget name it WBPU_ToolWidget

Blueprint setup

Create those variables names:

Now set the variables like below:

  • Menu

    • Type: Name

    • Value: LevelEditor.LevelEditorToolBar

  • Section

    • Type: Name

    • Value: MyTools

  • MenuEntry

    • Type: ToolMenuEntry

    • Value:

      • Name: Mytools

      • Type: ToolBarButton

      • UserInterfaceActionType: Button

  • Label

    • Type: Text

    • Value: MyTool

  • ToolTip

    • Type: Text

    • Value: Open MyTool

  • Icon

    • Type: ScriptSlateIcon
  • OptionWidget

    • Type: EditorUtilityWidgetBlueprint

    • Value: WBPU_ToolWidget

  • OptionWidgetID

    • Type: Name

Copy the following graph:

Add a space after KISMETEVENT

and before OpenWidgetOptions

Now you may try it: Close the editor and restart your project if a button appear like this:

Success if you can click the button and the widget window appear

If there is no button first verify DefaultEditorPerProjectUserSettings.ini add a print string node on the Event Run. Reload and search the OutputLog for the string. If you did not have to change the ini file to see the string the error may be one of the following in OutputLog:

  • "Hook menu not found" the variable menu value is wrong

  • "LogToolMenus: Warning: Toolbar 'LevelEditor.LevelEditorToolBar', item 'Mytools', type not currently supported: X" the variable MenuEntry is not setup correctly

If the button doesn't open the widget verify the append Node

  • If on click you see "Failed to find an object named 'BPU_TutoStartupHook_C_0OpenWidgetOptions'." You miss a space before OpenWidgetOptions

  • If the error is silent "Cmd: KISMETEVENTBPU_TutoStartupHook_C_0 BPUOpenWidgetOptions" You miss a space after KISMETEVENT

Further reading

Other menus

Now that you know how to create a toolbar button you can now do it for any kind of menu

e.g: You can add button in the main menu bar change the variable Menu to LevelEditor.MainMenu.Window and set accordingly MenuEntry Type to MenuEntry

you can search in the engine source for UToolMenus::Get()->RegisterMenu to find the available menus.

Specific Classes

  • This is a topic i do not master well.

  • A lot of the engine code is not exposed to blueprint

  • It may be change in future

You can create a button for a specific class to do that you need a context to find a matching class wich is provided by the ToolMenuEntryScript class you may subclass this and pass it to the MenuEntry ScriptObject variable.

Your ToolMenuEntryScript subclass has native event CanExecute and ConstructMenuEntry those provide the necessary context

Passing a scriptObject to the MenuEntry bypass the button creation from the node AddMenuEntry and as result it fire ConstructMenuEntry event.

  • Implement icon for the button

  • Support for other menus and specific classes

  • Support for Section