{"id":3792,"date":"2022-06-01T12:14:21","date_gmt":"2022-06-01T10:14:21","guid":{"rendered":"https:\/\/store.algosyntax.com\/?post_type=asx-lms-tutorial-cpt&#038;p=3792"},"modified":"2026-03-09T16:04:54","modified_gmt":"2026-03-09T14:04:54","slug":"ue5-how-to-add-reimport-button-to-right-click-menu","status":"publish","type":"asx-lms-tutorial-cpt","link":"https:\/\/store.algosyntax.com\/tutorials\/unreal-engine\/ue5-how-to-add-reimport-button-to-right-click-menu\/","title":{"rendered":"UE5 Custom Asset Add Reimport Button To Right-Click Menu"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"3792\" class=\"elementor elementor-3792\" data-elementor-post-type=\"asx-lms-tutorial-cpt\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-8ccb3cd elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"8ccb3cd\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-57d53c5\" data-id=\"57d53c5\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e374727 elementor-widget elementor-widget-text-editor\" data-id=\"e374727\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>This tutorial covers extending your unreal engine custom asset right-click menu and adding the reimport button to that menu. It is a continuation of the <a href=\"https:\/\/store.algosyntax.com\/tutorials\/unreal-engine\/tutorial-ue5-add-reimport-support-to-custom-asset\/\">How to add reimport functionality to a custom asset in unreal engine<\/a> tutorial. We assume you have read that tutorial or you have a custom asset with reimport functions and would like to move the reimport button from the asset editor window to its right-click menu. Remember,\u00a0 if at any point of our tutorials you get the unresolved external symbol error, which is either LNK2001 or LNK2019 error, You can follow the <a href=\"https:\/\/store.algosyntax.com\/tutorials\/unreal-engine\/ue5-lnk2001-unresolved-external-symbol-solution\/\">LNK2001\u00a0 Solution tutorial.\u00a0<\/a><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-6a56e76 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"6a56e76\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-2f58879\" data-id=\"2f58879\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-3099d3f elementor-widget elementor-widget-heading\" data-id=\"3099d3f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Inherit from FAssetTypeActions_Base<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2cc6913 elementor-widget elementor-widget-text-editor\" data-id=\"2cc6913\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>In order to extend custom asset right-click menu we are going to make use of the class <a href=\"https:\/\/docs.unrealengine.com\/5.0\/en-US\/API\/Developer\/AssetTools\/FAssetTypeActions_Base\/\" target=\"_blank\" rel=\"noopener\">FAssetTypeActions_Base.<\/a><\/p><p>This class inherits from <a href=\"https:\/\/docs.unrealengine.com\/5.0\/en-US\/API\/Developer\/AssetTools\/IAssetTypeActions\/\" target=\"_blank\" rel=\"noopener\">IAssetTypeActions<\/a> . They both have virtual functions we need to override to get this functionality but FAssetTypeActions_Base has some predefined logic built in.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-338987a elementor-widget elementor-widget-code-highlight\" data-id=\"338987a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-cpp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>\/\/FBcgAssetActions.h\r\n\r\nclass FBcgAssetActions : public FAssetTypeActions_Base\r\n{\r\n    virtual bool HasActions(const TArray<UObject*>& InObjects) const override { return true; }\r\n    \r\n    virtual void GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& MenuBuilder) override;\r\n\t\r\n};<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1b635c7 elementor-widget elementor-widget-heading\" data-id=\"1b635c7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Override HasActions() Virtual Function<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5625785 elementor-widget elementor-widget-text-editor\" data-id=\"5625785\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>We override the <a href=\"https:\/\/docs.unrealengine.com\/4.26\/en-US\/API\/Developer\/AssetTools\/IAssetTypeActions\/HasActions\/\" target=\"_blank\" rel=\"noopener\">HasActions() <\/a>function to let the editor know that this custom asset has actions. To do that just return &#8220;true&#8221;; Actions are functions that can be called on the asset to do something. Most of the time this something is done on the custom asset or to the custom asset. It&#8217;s a fancy word for functions to run on button click.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-02245d3 elementor-widget elementor-widget-heading\" data-id=\"02245d3\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Override GetActions() Virtual Function<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8f87aea elementor-widget elementor-widget-text-editor\" data-id=\"8f87aea\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p><a href=\"https:\/\/docs.unrealengine.com\/4.27\/en-US\/API\/Developer\/AssetTools\/FAssetTypeActions_Base\/GetActions\/\" target=\"_blank\" rel=\"noopener\">GetActions()<\/a> is our right-click menu populating function.<br \/>We will insert the Reimport button into the menu here. \u00a0MenuBuilder is passed in and we call addMenuEntry to add an entry.<br \/><br \/><\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6b34288 elementor-widget elementor-widget-code-highlight\" data-id=\"6b34288\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-cpp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>void FBcgAssetActions::GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& MenuBuilder)\r\n{\r\n\tFText ButtonLabel=FText::FromString(\"Reimport\/Replace\");\r\n\tFText ButtonToolTip=FText::FromString(\"Replaces this BcgAsset with a source on disk\");\r\n\r\n\tauto BcgAssets = GetTypedWeakObjectPtrs<UMidiAsset>(InObjects);\r\n\r\n\t\/\/The function to call on click. Our CallBackFunction. It will pass the selected BcgAsets on to our callback function. \r\n\tauto TDelegateExecuteAction=FExecuteAction::CreateSP(this,&FBcgAssetActions::ReimportBcgAsset, BcgAssets);\r\n\r\n\tauto UIAction=FUIAction(TDelegateExecuteAction);\r\n\r\n\tMenuBuilder.AddMenuEntry(ButtonLabel,ButtonToolTip,FSlateIcon(), UIAction);\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c39f2fd elementor-widget elementor-widget-text-editor\" data-id=\"c39f2fd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>Implementation of this function can get complicated because it requires some understanding of Templates, Shared Pointers and Delegates. We would rather cover this in our Plugin Development Course For Unreal Engine through video.<\/p><p>\u00a0<\/p><p>But to summarise we need to supply AddMenuEntry() function with some arguments.<\/p><p>The first is the label of the entry to add.\u00a0<\/p><p>The second is the tooltip the user will see when they hover.<\/p><p>For the 3rd, the SlateIcon, just call the default constructor.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-32623b2 elementor-widget elementor-widget-text-editor\" data-id=\"32623b2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>The 4th Argument, the <a href=\"https:\/\/docs.unrealengine.com\/4.27\/en-US\/API\/Runtime\/Slate\/Framework\/Commands\/FUIAction\/\" target=\"_blank\" rel=\"noopener\">FUIAction<\/a> is the tricky part.<\/p><p>We&#8217;ll cover the steps needed to create a FUIAction object that is needed by AddMenuEntry function.<\/p><ol><li>FUIAction is created by passing in an object of\u00a0 FExecuteAction.<br \/><br \/><\/li><li>To Create an object of FExecuteAction, we call the static function FExecuteAction::CreateSP()<br \/><br \/><\/li><li>The FExecuteAction::CreateSP() function, is where we specify our callback function. I.e We specify the function to call when a button is clicked.<br \/><br \/><\/li><li>The last argument in the CreateSP function is the payload, in our case the BcgAssets we want to pass on the callback function.<br \/><br \/><\/li><li>Finally, create an object of FUIAction by passing in the object of FExecuteAction as the constructor argument;<\/li><\/ol><p><a href=\"https:\/\/docs.unrealengine.com\/4.26\/en-US\/API\/Runtime\/Slate\/Framework\/Commands\/FExecuteAction\/\" target=\"_blank\" rel=\"noopener\">FExecuteAction<\/a>\u00a0 is just a fancy delegate for Slate. When we create this delegate we immediately bind a function to it.<\/p><p>Your call-back function may need to receive payloads; We also specify these during the creation of the delegate.<\/p><p>We will cover the specifics of why to use CreateSP,\u00a0 or how to use the other options in the course.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-98b5b12 elementor-widget elementor-widget-heading\" data-id=\"98b5b12\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">What you need to do in the callback function<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-437f756 elementor-widget elementor-widget-text-editor\" data-id=\"437f756\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>When the user clicks your menu entry, this call back function will get called. In our case, we want to initiate the reimport functionality for all of our selected custom assets. This is how you do it:<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4c645d9 elementor-widget elementor-widget-code-highlight\" data-id=\"4c645d9\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-cpp line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-cpp\">\n\t\t\t\t\t<xmp>\r\n\r\nvoid FBcgAssetActions::ReimportBcgAsset(TArray<TWeakObjectPtr<UBcgAsset>> BcgAssetsWeakPtrs)\r\n{\r\n\tfor (auto BcgAssetWeakPtr : BcgAssetsWeakPtrs)\r\n\t{\r\n\t\tUBcgAsset* BcgAsset= BcgAssetWeakPtr.Get();\r\n\r\n\t\tif(BcgAsset)\r\n\t\t{\r\n\t\t\tFReimportManager::Instance()->Reimport(BcgAsset,true);\r\n\t\t}\r\n\t}\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-9fbfa87 elementor-widget elementor-widget-text-editor\" data-id=\"9fbfa87\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>You need to loop through all your objects and call Reimport() on the instance of FReimportManager.\u00a0 Most of the code here is just us converting from weak pointers to raw pointers. The most important part is the Reimport function.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f373526 elementor-widget elementor-widget-heading\" data-id=\"f373526\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Register Your Asset Actions<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d9c89a5 elementor-widget elementor-widget-text-editor\" data-id=\"d9c89a5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>You have now made it to the final part. You just need to go to your module implementation and register your Custom Asset Actions with AssetTools. You can do this when the module is starting up.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fb80dbe elementor-widget elementor-widget-heading\" data-id=\"fb80dbe\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Conclusion<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ffd1d9a elementor-widget elementor-widget-text-editor\" data-id=\"ffd1d9a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>The Unreal Engine Plugin Development course covers more in-depth explanations for you to understand most datatypes and what unreal engine is doing under the hood but you can still get by, with these tutorials.\u00a0<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"featured_media":0,"template":"","asx-lms-tutorial-categories":[55,58,45],"asx-lms-tutorial-tags":[46],"class_list":["post-3792","asx-lms-tutorial-cpt","type-asx-lms-tutorial-cpt","status-publish","hentry","asx-lms-tutorial-categories-plugin-development","asx-lms-tutorial-categories-unreal-c-api","asx-lms-tutorial-categories-unreal-engine","asx-lms-tutorial-tags-cpp","entry"],"acf":[],"_links":{"self":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-cpt\/3792","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-cpt"}],"about":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/types\/asx-lms-tutorial-cpt"}],"version-history":[{"count":0,"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-cpt\/3792\/revisions"}],"wp:attachment":[{"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/media?parent=3792"}],"wp:term":[{"taxonomy":"asx-lms-tutorial-categories","embeddable":true,"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-categories?post=3792"},{"taxonomy":"asx-lms-tutorial-tags","embeddable":true,"href":"https:\/\/store.algosyntax.com\/asx-rest\/wp\/v2\/asx-lms-tutorial-tags?post=3792"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}