Project Toolbar Button

16 Aug 2024

Since Unreal’s Editor Widget Blueprints were introduced the barrier to entry for custom tooling has significantly decreased compared to writing C++ Editor Slate code. I’ve created a sizable collection of different custom editors and helper widgets for the various projects I’m working on. Most of them are highly specific to make editing custom asset types easier.

However, with the number of widgets increasing it also starts to become more and more frustrating to find and launch them via Right Click -> Run Widget. So what better way to offload that than into another editor widget? So I’ve created a button collection widget where each button launches one of the other widgets.

Still I found myself opening and closing that window a lot. Launching one widget instead of many was less fun than I had hoped. So what about putting it in the editor toolbar?


Creating the Toolbar Button

This step is actually quite easy since Unreal’s plugin creation wizard already gives us all the boilerplate code. We simply go to Edit -> Plugins and click the Add button. Then choose Editor Toolbar Button and name it something like MyEditorTools and click Create Plugin.

Step by step clicking the new plugin button, then selecting the toolbar button preset and finally the create button.


Tada! After the code is compiled we’ll have a fresh toolbar button.

Screenshot of the placeholder tool button on the Unreal Editor Toolbar


Running the Editor Widget

When the button is clicked it pops up a little notification that tells us how to change its behavior. The button calls a function named PluginButtonClicked in MyEditorTools.cpp. This is where we’ll open our editor widget.

void FMyEditorToolsModule::PluginButtonClicked()
{
	// Put your "OnButtonClicked" stuff here
	FText DialogText = FText::Format(
					LOCTEXT("PluginButtonDialogText", "Add code to {0} in {1} to override this button's actions"),
					FText::FromString(TEXT("FMyEditorToolsModule::PluginButtonClicked()")),
					FText::FromString(TEXT("MyEditorTools.cpp"))
				   );
	FMessageDialog::Open(EAppMsgType::Ok, DialogText);
}

To be able to open Blueprint Editor Widgets we’ll need to add some dependencies to the plugin.

First in the MyEditorTools.uplugin, we’ll need to add the Editor Scripting Utilities as a dependent plugin:

"Plugins": [
	{
		"Name": "EditorScriptingUtilities",
		"Enabled": true
	}
]

Next we need to add UMGEditor, EditorScriptingUtilities and Blutility to the PrivateDependencyModuleNames list in Plugins/MyEditorTools/Source/MyEditorTools/MyEditorToolsModule.Build.cs. It should look like this:

PrivateDependencyModuleNames.AddRange(
	new string[]
	{
		"Projects",
		"InputCore",
		"EditorFramework",
		"UnrealEd",
		"ToolMenus",
		"CoreUObject",
		"Engine",
		"Slate",
		"SlateCore",
		"UMGEditor",
		"EditorScriptingUtilities",
		"Blutility",
		// ... add private dependencies that you statically link with here ...	
	}
);

Which brings us back to MyEditorTools.cpp. After adding the dependencies we’ll add the following includes:

#include "Editor.h"
#include "EditorAssetLibrary.h"
#include "EditorUtilitySubsystem.h"
#include "EditorUtilityWidgetBlueprint.h"

Next we’ll need the reference path to the Editor Widget that we want to launch. To get that we Right Click on the widget asset and choose Copy Reference. It should put a path into the clipboard looking something like this:

/Script/Blutility.EditorUtilityWidgetBlueprint'/MyEditorTools/MainEditor/EWB_MyEditor.EWB_MyEditor'

We remove the “/Script/Blutility.” part from the path and paste it into the LoadAsset function. This code replaces the stub in the PluginButtonClicked function.

void FMyEditorToolsModule::PluginButtonClicked()
{
	//Load the editor widget asset
	UObject * Blueprint = UEditorAssetLibrary::LoadAsset(FString(TEXT("EditorUtilityWidgetBlueprint'/MyEditorTools/MainEditor/EWB_MyEditor.EWB_MyEditor'")));
	if(IsValid(Blueprint)) 
	{
		//Make sure it's actually an editor widget
		UEditorUtilityWidgetBlueprint* EditorWidget = Cast<UEditorUtilityWidgetBlueprint>(Blueprint);
		if (IsValid(EditorWidget)) 
		{
			//Use the utility subsystem to spawn the widget
			UEditorUtilitySubsystem* EditorUtilitySubsystem = GEditor->GetEditorSubsystem<UEditorUtilitySubsystem>();
			EditorUtilitySubsystem->SpawnAndRegisterTab(EditorWidget);
		}
	}
}

After compiling the toolbar button should now launch the editor widget.


Custom Tooltip

When hovering over the button a tooltip is displayed. By default it will say “Execute MyEditorTools action”. We can change what it says by editing the text in the RegisterCommands method in MyEditorToolsCommands.cpp:

void FMyEditorToolsCommands::RegisterCommands()
{
	UI_COMMAND(PluginAction, "MyEditorTools", "Execute MyEditorTools action", EUserInterfaceActionType::Button, FInputChord());
}


Custom Icon

The toolbar button displays as some slanted grey lines. In order to give it a more personal look we edit MyEditorToolsStyle.cpp. FMyEditorToolsStyle::Create creates a new slate style sheet and loads the button icon file as a brush with the id “MyEditorTools.PluginAction”. The folder this image is loaded from is Plugins/MyEditorTools/Resources/.

TSharedRef< FSlateStyleSet > FMyEditorToolsStyle::Create()
{
	TSharedRef< FSlateStyleSet > Style = MakeShareable(new FSlateStyleSet("MyEditorToolsStyle"));
	Style->SetContentRoot(IPluginManager::Get().FindPlugin("MyEditorTools")->GetBaseDir() / TEXT("Resources"));

	Style->Set("MyEditorTools.PluginAction", new IMAGE_BRUSH_SVG(TEXT("PlaceholderButtonIcon"), Icon20x20));
	return Style;
}

To load a different image we put it into the folder. Screenshot of the plugin's resource folder with a bee icon.

To load it we create a new IMAGE_BRUSH and use the file name without the extension.

Style->Set("MyEditorTools.PluginAction", new IMAGE_BRUSH(TEXT("ToolbarIcon"), Icon20x20));

In case the icon is an SVG, we use IMAGE_BRUSH_SVG instead.

Style->Set("MyEditorTools.PluginAction", new IMAGE_BRUSH_SVG(TEXT("PlaceholderButtonIcon"), Icon20x20));


And there we have it. One more compile and the custom button is done!✨ Screenshot of the toolbar button with a bee icon and custom tooltip