UE uses path format to extend the menu.
Document how to implement path-driven expanded menu in UE.
If you are not familiar with the UE extension menu, it is recommended to take a brief look at: UE Extension Editor Menu
This text is based on the plugin: UE.EditorPlus
Node Management
Manage the menu in a tree structure, where parent nodes can contain children:
class EDITORPLUS_API FEditorPlusMenuBase: public TSharedFromThis<FEditorPlusMenuBase>
{
protected:
// sub menus
TArray<TSharedRef<FEditorPlusMenuBase>> Children;
}
Create child nodes while creating the parent node:
void FEditorPlusMenuBase::Register(FMenuBuilder& MenuBuilder)
{
for (const auto Menu: Children)
{
Menu->Register(MenuBuilder);
}
}
Of course, the specific creation behavior of each node will vary slightly, implemented by overriding virtual functions:
// Menubar
void FEditorPlusMenuBar::Register(FMenuBarBuilder& MenuBarBuilder)
{
MenuBarBuilder.AddPullDownMenu(
GetFriendlyName(),
GetFriendlyTips(),
// Delegate to call Register
FEditorPlusMenuManager::GetDelegate<FNewMenuDelegate>(GetUniqueId()),
Hook);
}
// Section
void FEditorPlusSection::Register(FMenuBuilder& MenuBuilder)
{
MenuBuilder.BeginSection(Hook, GetFriendlyName());
FEditorPlusMenuBase::Register(MenuBuilder);
MenuBuilder.EndSection();
}
// Separator
void FEditorPlusSeparator::Register(FMenuBuilder& MenuBuilder)
{
MenuBuilder.AddMenuSeparator(Hook);
FEditorPlusMenuBase::Register(MenuBuilder);
}
// SubMenu
void FEditorPlusSubMenu::Register(FMenuBuilder& MenuBuilder)
{
MenuBuilder.AddSubMenu(
GetFriendlyName(),
GetFriendlyTips(),
FNewMenuDelegate::CreateSP(this, &FEditorPlusSubMenu::MakeSubMenu),
false,
FSlateIcon(),
true,
Hook
);
}
// Command
void FEditorPlusCommand::Register(FMenuBuilder& MenuBuilder)
{
MenuBuilder.AddMenuEntry(
CommandInfo->Label, CommandInfo->Tips, CommandInfo->Icon,
CommandInfo->ExecuteAction, CommandInfo->Hook, CommandInfo->Type);
}
// ......
Generate nodes through the path.
Organize the menu in a tree structure format, and the path format can define the tree structure of a menu.
The above path can be used to define the creation of a series of menus:
<Hook>Help
: Located after the menu named Help in the Hook.<MenuBar>BarTest
: Creates a menu of type MenuBar, named BarTest.<SubMenu>SubTest
: Create a child node, type SubMenu, name SubTest.<Command>Action
: Finally, create a command.
The form of the interface call can be quite simple:
const FString Path = "/<Hook>Help/<MenuBar>BarTest/<SubMenu>SubTest/<Command>Action";
FEditorPlusPath::RegisterPathAction(
Path,
FExecuteAction::CreateLambda([]
{
// do action
})
);
Generate nodes using custom form.
We still retain a cumbersome way to create menus, which allows for more detailed settings. The organization of the code somewhat resembles the way of writing SlateUI in UE.
EP_NEW_MENU(FEditorPlusMenuBar)("BarTest")
->RegisterPath()
->Content({
EP_NEW_MENU(FEditorPlusSubMenu)("SubTest")
->Content({
EP_NEW_MENU(FEditorPlusCommand)("Action")
->BindAction(FExecuteAction::CreateLambda([]
{
// do action
})),
})
});
Hybrid form
Of course, the path format and the custom-generated menus are essentially the same, and they can be mixed and matched with great flexibility.
FEditorPlusPath::RegisterPath(
"/<MenuBar>BarTest/<SubMenu>SubMenu/<Command>Action1",
EP_NEW_MENU(FEditorPlusCommand)("Action1")
->BindAction(FExecuteAction::CreateLambda([]
{
// do action
})),
);
FEditorPlusPath::RegisterPath(
"/<MenuBar>BarTest/<SubMenu>SubMenu/<Command>Action2",
EP_NEW_MENU(FEditorPlusCommand)("Action2")
->BindAction(FExecuteAction::CreateLambda([]
{
// do action
})),
);
Menus defined in multiple locations will be merged into the same hierarchical structure, and nodes with the same name will be considered as the same node. In other words, the path is unique, and the same path can uniquely identify a menu node. We can also identify the nodes and make some adjustments and modifications.
// set Name and Tips
FEditorPlusPath::GetNodeByPath("/<MenuBar>BarTest")->SetFriendlyName(LOCTEXT("MenuTest", "MenuTest"))->SetFriendlyTips(LOCTEXT("MenuTestTips", "MenuTestTips"));
Original: https://wiki.disenone.site/en
This post is protected by CC BY-NC-SA 4.0 agreement, should be reproduced with attribution.
Visitors. Total Visits. Page Visits.
This post was translated using ChatGPT, please provide feedback in FeedbackPoint out any omissions.