Is it possible to add a new item to an existing toolbar submenu?

So I’m looking through some of the code that constructs the default editor toolbar menus and wondering if it’s possible to add an item to one of them via a plugin.

Is there an overview of the command/menu/interface structure somewhere? I work much better with imagery and this area seems to be particularly complex. If there isn’t, if someone helps me understand it I’ll draw one up and throw it on the wiki.

It sort of seems like the way to go is to loop through the toolbar and reconstruct it, while adding my changes. Would that make sense? Is there any way to just intercept the ONE delegate I want to replace?

1 Like

I think what I need is a way to create a new MenuBuilder object and somehow associate it with a child of an existing structure, then just AddMenuItem(). It doesn’t look like there’s any way to navigate the slate hierarchy though?

Basically, you want to use FExtender class and add extension through it. For example, if you would like to add menu entry to “File” menu on the top of Unreal Editor, you would do something like this:

  1. Create Extender:

TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());

  1. Add extension to your extender

MenuExtender->AddMenuExtension("FileProject", EExtensionHook::After, MyPluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FPluginCreatorModule::AddMenuExtension));

  1. Add extender to actural level editor menu

FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);

You should also check out twitch stream on Extending editor with Michael Noland, it’s extremly helpful on understanding how does editor works.

Cheers

2 Likes

Thanks for your reply! That’s basically what I had. I changed a couple of things up but it’s still not appearing in the target submenu. I just found a potential collision between my command name and a command handler though, so I’ll fix that real quick. Nope, that wasn’t it.

Can you tell me a bit about commands? When you do MapAction(), is it kind of a singleton or can you map multiple actions? In my instance I’m creating a new FUICommandList just for this menu item. (Edit: Actually, I’ve switched to just using one FUICommandList object, same result but tidier code).

Also, under RegisterCommands() does it matter what EUserInterfaceActionType I use? The menu I’m adding to actually has radio buttons in it, but that’s a problem for later, so for now I’m using EUserInterfaceActionType::Button. Will that still work?

By the same token can I re-use the MenuExtender, or do I need a new one for each item I’m adding? If I can, do I call AddExtender once at the end, or for each item? I’m guessing yes, as you pass in PluginCommands so that it can create the menubuilder used by the delegate, which then references a specific command from the list by name.

Does it matter that the submenu I’m trying to insert into is a toolbar submenu? I tried converting everything into toolbar-y stuff but didn’t get very far.

As you can see I’m down to checking obvious specifics.

UICommands are just a set of action mappings so you can use it multiple times in different places. Either in form of a menu button or shortcut - for example, note that file and edit menu on the top menu bar are the same in level editor window and in blueprint editor.
Also note that you’re using something thats called FUICommandList which means you can put there any number of commands there. When you use MapAction you’re binding a function to given command, I’m not sure what do you mean by “mapping multiple actions”. But keep in mind that if you want to extend any menu you dont have to use UICommands. Yes, it is recommended but you dont have to.

If you want radio buttons you should use EUserInterfaceActionType::RadioButton, if you just want to display a menu entry, go with Button or Toggle button. I can’t really tell what and how you’re doing stuff without seeing your code.

You can add any number of entries to a given extender. You do that in the function youre binding when calling AddMenuExtension (&FPluginCreatorModule::AddMenuExtension in the example above)

It shouldnt matter as long as youre using correct extender: MenuExtender for menus and ToolbarEtender for toolbars.

You should take a look at samples provided in STestSuite.cpp file in the source code. You will find there everything you need to get started with slate menus.

If you will still have problems, please, paste your code so I can get better understanding of what you’re trying to achieve.

1 Like

I had a quick look through the tests already but I don’t think it has an example of modifying an existing submenu. Here’s some code:


/* Lighting quality menu option */TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
PluginCommands->MapAction(
    FMyThingRenderPluginCommands::Get().UseMyThingLighting,
    FExecuteAction::CreateRaw(this, &FMyThingRenderPluginModule::UseMyThingLightingSelected),
    FCanExecuteAction());
MenuExtender->AddMenuExtension("LevelEditorBuildLightingQuality", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FMyThingRenderPluginModule::AddLightingMenuExtension));


LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);


void FMyThingRenderPluginModule::UseMyThingLightingSelected()
{
    // Handle menu action
}
void FMyThingRenderPluginModule::AddLightingMenuExtension(FMenuBuilder& Builder)
{
    Builder.AddMenuEntry(FMyThingRenderPluginCommands::Get().UseMyThingLighting, "LevelEditorBuildLightingQuality");
}


UI_COMMAND(UseMyThingLighting, "MyThing", "Do some stuff", EUserInterfaceActionType::Button, FInputGesture());

The net effect is nothing happens. No errors or warnings, just zilch. It makes me wonder if this particular menu is somehow static and not ever updated.

With most things so far I’ve found that the problem is just with my understanding of it. So far everything you’ve said has made sense and confirmed what i thought, so let’s check my thinking in this case:

  1. Most of slate has event hooks for when an element is instantiated, in case it’s been modified, yeah?
  2. In this case due to what I can see with how the menu I want to change is constructed, it might not be accessible in the same way.

Would that be right, or are they all the same and all accessible?

LevelEditorBuildLightingQuality menu is a submenu and if you go to LevelEditorToolBar.cpp you’ll see that it is hardcoded and theres no way to extend it. However, you shoud be able to extend Lighting menu.

Keep in mind that GetMenuExtensibilityManager refers to the top menu with File, Edit and View options, when GetToolBarExtensibilityManager refers to the toolbar with Play, compile and build lighting buttons.

Nah, I would say you’ve got only few places that you can extend editor UI. But if you think about, it’s actually pretty reasonable and sufficient in most cases. Imagine that you have extension manager for each menu/submenu in the editor, that would take quite big amount of code to do. And how often potential Editor user would like to extend LightingBuildInfo submenu? Well, not very often, I guess ; )

My advice would be to go ahead and create your own button/menu for toolbar and get things done there. It will be easier to implement for your and easier to access for users in the future.

Gotcha. You’ve pretty much confirmed what I thought, so I’m not totally lost. :slight_smile:

Would destroying the submenu and rebuilding it entirely at runtime be an option? Otherwise yeah, a button is going to have to be it, although it really does belong in that particular menu.