{"id":909,"date":"2019-12-12T16:39:52","date_gmt":"2019-12-12T16:39:52","guid":{"rendered":"https:\/\/www.danielparente.net\/en\/2019\/12\/12\/how-to-make-tools-in-ue4\/"},"modified":"2019-12-12T16:39:52","modified_gmt":"2019-12-12T16:39:52","slug":"how-to-make-tools-in-ue4","status":"publish","type":"post","link":"https:\/\/www.danielparente.net\/en\/2019\/12\/12\/how-to-make-tools-in-ue4\/","title":{"rendered":"How to Make Tools in UE4"},"content":{"rendered":"<p> [ad_1]<br \/>\n<\/p>\n<div>\n<div class=\"paragraph\">\n<p>Next we are going to add a custom menu, so we can add widget in the menu to run a command or open up a window.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>First we need to add menu extensions related functions in our editor module <strong>ToolExampleEditor<\/strong>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<p>ToolExampleEditor.h<\/p>\n<div class=\"content\">\n<pre class=\"prettyprint highlight\"><code class=\"language-cpp\" data-lang=\"cpp\">public:\n    void AddMenuExtension(const FMenuExtensionDelegate &amp;extensionDelegate, FName extensionHook, const TSharedPtr&lt;FUICommandList&gt; &amp;CommandList = NULL, EExtensionHook::Position position = EExtensionHook::Before);\n    TSharedRef&lt;FWorkspaceItem&gt; GetMenuRoot() { return MenuRoot; };\n\nprotected:\n    TSharedPtr&lt;FExtensibilityManager&gt; LevelEditorMenuExtensibilityManager;\n    TSharedPtr&lt;FExtender&gt; MenuExtender;\n\n    static TSharedRef&lt;FWorkspaceItem&gt; MenuRoot;\n\n    void MakePulldownMenu(FMenuBarBuilder &amp;menuBuilder);\n    void FillPulldownMenu(FMenuBuilder &amp;menuBuilder);<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>In the cpp file, define <strong>MenuRoot<\/strong> and add the implement all the functions. Here we will add a menu called &#8220;Example&#8221; and create 2 sections: &#8220;Section 1&#8221; and &#8220;Section 2&#8221;, with extension hook name &#8220;Section_1&#8221; and &#8220;Section_2&#8221;.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<p>ToolExampleEditor.cpp<\/p>\n<div class=\"content\">\n<pre class=\"prettyprint highlight\"><code class=\"language-cpp\" data-lang=\"cpp\">TSharedRef&lt;FWorkspaceItem&gt; FToolExampleEditor::MenuRoot = FWorkspaceItem::NewGroup(FText::FromString(\"Menu Root\"));\n\n\nvoid FToolExampleEditor::AddMenuExtension(const FMenuExtensionDelegate &amp;extensionDelegate, FName extensionHook, const TSharedPtr&lt;FUICommandList&gt; &amp;CommandList, EExtensionHook::Position position)\n{\n    MenuExtender-&gt;AddMenuExtension(extensionHook, position, CommandList, extensionDelegate);\n}\n\nvoid FToolExampleEditor::MakePulldownMenu(FMenuBarBuilder &amp;menuBuilder)\n{\n    menuBuilder.AddPullDownMenu(\n        FText::FromString(\"Example\"),\n        FText::FromString(\"Open the Example menu\"),\n        FNewMenuDelegate::CreateRaw(this, &amp;FToolExampleEditor::FillPulldownMenu),\n        \"Example\",\n        FName(TEXT(\"ExampleMenu\"))\n    );\n}\n\nvoid FToolExampleEditor::FillPulldownMenu(FMenuBuilder &amp;menuBuilder)\n{\n    \/\/ just a frame for tools to fill in\n    menuBuilder.BeginSection(\"ExampleSection\", FText::FromString(\"Section 1\"));\n    menuBuilder.AddMenuSeparator(FName(\"Section_1\"));\n    menuBuilder.EndSection();\n\n    menuBuilder.BeginSection(\"ExampleSection\", FText::FromString(\"Section 2\"));\n    menuBuilder.AddMenuSeparator(FName(\"Section_2\"));\n    menuBuilder.EndSection();\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Finally in <strong>StartupModule<\/strong> we add the following before we call the parent function. We add our menu after &#8220;Window&#8221; menu.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<p>ToolExampleEditor.cpp<\/p>\n<div class=\"content\">\n<pre class=\"prettyprint highlight\"><code class=\"language-cpp\" data-lang=\"cpp\">void FToolExampleEditor::StartupModule()\n{\n    if (!IsRunningCommandlet())\n    {\n        FLevelEditorModule&amp; LevelEditorModule = FModuleManager::LoadModuleChecked&lt;FLevelEditorModule&gt;(\"LevelEditor\");\n        LevelEditorMenuExtensibilityManager = LevelEditorModule.GetMenuExtensibilityManager();\n        MenuExtender = MakeShareable(new FExtender);\n        MenuExtender-&gt;AddMenuBarExtension(\"Window\", EExtensionHook::After, NULL, FMenuBarExtensionDelegate::CreateRaw(this, &amp;FToolExampleEditor::MakePulldownMenu));\n        LevelEditorMenuExtensibilityManager-&gt;AddExtender(MenuExtender);\n    }\n    IExampleModuleInterface::StartupModule();\n}<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Now if you run it you should see the custom menu get added with two sections.<\/p>\n<\/div>\n<div class=\"imageblock\" style=\"text-align: left\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/github.com\/lxjk\/lxjk.github.io\/raw\/master\/images\/ue4tools\/002.png\" alt=\"002.png\" width=\"329\"\/><\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Next we can add our first tool to register to our menu. First add two new files:<\/p>\n<\/div>\n<div class=\"imageblock\" style=\"text-align: left\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/github.com\/lxjk\/lxjk.github.io\/raw\/master\/images\/ue4tools\/003.png\" alt=\"003.png\" width=\"190\"\/><\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>This class will inherit from <strong>IExampleModuleListenerInterface<\/strong>, and we add function to create menu entry. We also add <strong>FUICommandList<\/strong>, which will define and map a menu item to a function. Finally we add our only menu function <strong>MenuCommand1<\/strong>, this function will be called when user click on the menu item.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<p>MenuTool.h<\/p>\n<div class=\"content\">\n<pre class=\"prettyprint highlight\"><code class=\"language-cpp\" data-lang=\"cpp\">#include \"ToolExampleEditor\/IExampleModuleInterface.h\"\n\nclass MenuTool : public IExampleModuleListenerInterface, public TSharedFromThis&lt;MenuTool&gt;\n{\npublic:\n    virtual ~MenuTool() {}\n\n    virtual void OnStartupModule() override;\n    virtual void OnShutdownModule() override;\n\n    void MakeMenuEntry(FMenuBuilder &amp;menuBuilder);\n\nprotected:\n    TSharedPtr&lt;FUICommandList&gt; CommandList;\n\n    void MapCommands();\n\n    \/\/ UI Command functions\n    void MenuCommand1();\n};<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>On the cpp side, we got a lot more to do. First we need to define <strong>LOCTEXT_NAMESPACE<\/strong> at the beginning, and un-define it at the end. This is required to use <strong>UI_COMMAND<\/strong> macro.<br \/>\nThen we start filling in each command, first create a <strong>FUICommandInfo<\/strong> member for each command in command list class, fill in <strong>RegisterCommands<\/strong> function by using <strong>UI_COMMAND<\/strong> marcro. Then in <strong>MapCommands<\/strong> function map each command info to a function. And of course define the command function <strong>MenuTool::MenuCommand1<\/strong>.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In <strong>OnStartupModule<\/strong>, we create command list, register it, map it, then register to menu extension. In this case we want our item in &#8220;Section 1&#8221;, and <strong>MakeMenuEntry<\/strong> will be called when Unreal build the menu, in which we simply add <strong>MenuCommand1<\/strong> to the menu.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>In <strong>OnShutdownModule<\/strong>, we need to unregister command list.<\/p>\n<\/div>\n<div class=\"listingblock\">\n<p>MenuTool.cpp<\/p>\n<div class=\"content\">\n<pre class=\"prettyprint highlight\"><code class=\"language-cpp\" data-lang=\"cpp\">#include \"ToolExampleEditor\/ToolExampleEditor.h\"\n#include \"MenuTool.h\"\n\n#define LOCTEXT_NAMESPACE \"MenuTool\"\n\nclass MenuToolCommands : public TCommands&lt;MenuToolCommands&gt;\n{\npublic:\n\n    MenuToolCommands()\n        : TCommands&lt;MenuToolCommands&gt;(\n        TEXT(\"MenuTool\"), \/\/ Context name for fast lookup\n        FText::FromString(\"Example Menu tool\"), \/\/ Context name for displaying\n        NAME_None,   \/\/ No parent context\n        FEditorStyle::GetStyleSetName() \/\/ Icon Style Set\n        )\n    {\n    }\n\n    virtual void RegisterCommands() override\n    {\n        UI_COMMAND(MenuCommand1, \"Menu Command 1\", \"Test Menu Command 1.\", EUserInterfaceActionType::Button, FInputGesture());\n\n    }\n\npublic:\n    TSharedPtr&lt;FUICommandInfo&gt; MenuCommand1;\n};\n\nvoid MenuTool::MapCommands()\n{\n    const auto&amp; Commands = MenuToolCommands::Get();\n\n    CommandList-&gt;MapAction(\n        Commands.MenuCommand1,\n        FExecuteAction::CreateSP(this, &amp;MenuTool::MenuCommand1),\n        FCanExecuteAction());\n}\n\nvoid MenuTool::OnStartupModule()\n{\n    CommandList = MakeShareable(new FUICommandList);\n    MenuToolCommands::Register();\n    MapAction();\n    FToolExampleEditor::Get().AddMenuExtension(\n        FMenuExtensionDelegate::CreateRaw(this, &amp;MenuTool::MakeMenuEntry),\n        FName(\"Section_1\"),\n        CommandList);\n}\n\nvoid MenuTool::OnShutdownModule()\n{\n    MenuToolCommands::Unregister();\n}\n\nvoid MenuTool::MakeMenuEntry(FMenuBuilder &amp;menuBuilder)\n{\n    menuBuilder.AddMenuEntry(MenuToolCommands::Get().MenuCommand1);\n}\n\nvoid MenuTool::MenuCommand1()\n{\n    UE_LOG(LogClass, Log, TEXT(\"clicked MenuCommand1\"));\n}\n\n#undef LOCTEXT_NAMESPACE<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>When this is all done, remember to add this tool as a listener to editor module in <strong>FToolExampleEditor::AddModuleListeners<\/strong>:<\/p>\n<\/div>\n<div class=\"listingblock\">\n<p>ToolExampleEditor.cpp<\/p>\n<div class=\"content\">\n<pre class=\"prettyprint highlight\"><code class=\"language-cpp\" data-lang=\"cpp\">ModuleListeners.Add(MakeShareable(new MenuTool));<\/code><\/pre>\n<\/div>\n<\/div>\n<div class=\"paragraph\">\n<p>Now if you build the project, you should see your menu item in the menu. And if you click on it, it will print &#8220;clicked MenuCommand1&#8221;.<\/p>\n<\/div>\n<div class=\"paragraph\">\n<p>By now you have a basic framework for tools, You can run anything you want based on a menu click.<\/p>\n<\/div>\n<div class=\"imageblock\" style=\"text-align: left\">\n<div class=\"content\">\n<img decoding=\"async\" src=\"https:\/\/github.com\/lxjk\/lxjk.github.io\/raw\/master\/images\/ue4tools\/004.png\" alt=\"004.png\" width=\"236\"\/><\/div>\n<\/div>\n<\/div>\n<p>[ad_2]<br \/>\n<br \/><a href=\"https:\/\/lxjk.github.io\/2019\/10\/01\/How-to-Make-Tools-in-U-E.html\" target=\"_blank\" rel=\"noopener\">Source link <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>[ad_1] Next we are going to add a custom menu, so we can add widget in the menu to run a command or open up a window. First we need to add menu extensions related functions in our editor module ToolExampleEditor: ToolExampleEditor.h public: void AddMenuExtension(const FMenuExtensionDelegate &amp;extensionDelegate, FName extensionHook, const TSharedPtr&lt;FUICommandList&gt; &amp;CommandList = NULL, EExtensionHook::Position [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":910,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_post_was_ever_published":false},"categories":[18],"tags":[],"class_list":["post-909","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-gamedev"],"blocksy_meta":[],"jetpack_featured_media_url":"https:\/\/e928cfdc7rs.exactdn.com\/info\/uploads\/sites\/3\/2019\/12\/How-to-Make-Tools-in-UE4.png?strip=all","jetpack_shortlink":"https:\/\/wp.me\/p2TFCd-eF","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/posts\/909","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/comments?post=909"}],"version-history":[{"count":0,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/posts\/909\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/media\/910"}],"wp:attachment":[{"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/media?parent=909"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/categories?post=909"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.danielparente.net\/en\/wp-json\/wp\/v2\/tags?post=909"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}