Creating custom context menu entries for Assets

Custom Asset types commonly have special functions you wish to be able to perform on them. For example, converting images to sprites is an option you wouldn't want to add to any other Asset type. You can create custom context menu entries for specific Asset types in order to make those functions accessible to users.

How to do it…

  1. Create a new class based on FAssetTypeActions_Base. You'll need to include AssetTypeActions_Base.h in the header file.
  2. Override the following virtual functions in the class:
    virtual bool HasActions(const TArray<UObject*>& InObjects) const override;
    virtual void GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& MenuBuilder) override;
    virtual FText GetName() const override;
    virtual UClass* GetSupportedClass() const override;
    
    virtual FColor GetTypeColor() const override;
    virtual uint32 GetCategories() override;
  3. Declare the following function:
    void MyCustomAssetContext_Clicked();
  4. Implement the declared functions in the .cpp file:
    bool FMyCustomAssetActions::HasActions(const TArray<UObject*>& InObjects) const
    {
      return true;
    }
    
    void FMyCustomAssetActions::GetActions(const TArray<UObject*>& InObjects, FMenuBuilder& MenuBuilder)
    {
      MenuBuilder.AddMenuEntry(
      FText::FromString("CustomAssetAction"),
      FText::FromString("Action from Cookbook Recipe"),
      FSlateIcon(FEditorStyle::GetStyleSetName(), "LevelEditor.ViewOptions"),
      FUIAction(
      FExecuteAction::CreateRaw(this, &FMyCustomAssetActions::MyCustomAssetContext_Clicked),
      FCanExecuteAction()));
    }
    
    uint32 FMyCustomAssetActions::GetCategories()
    {
      return EAssetTypeCategories::Misc;
    }
    FText FMyCustomAssetActions::GetName() const
    {
      return FText::FromString(TEXT("My Custom Asset"));
    }
    UClass* FMyCustomAssetActions::GetSupportedClass() const
    {
      return UMyCustomAsset::StaticClass();
    }
    
    FColor FMyCustomAssetActions::GetTypeColor() const
    {
      return FColor::Emerald;
    }
    voidFMyCustomAssetActions::MyCustomAssetContext_Clicked()
    {
      TSharedRef<SWindow> CookbookWindow = SNew(SWindow)
      .Title(FText::FromString(TEXT("Cookbook Window")))
      .ClientSize(FVector2D(800, 400))
      .SupportsMaximize(false)
      .SupportsMinimize(false);
    
      IMainFrameModule& MainFrameModule = FModuleManager::LoadModuleChecked<IMainFrameModule>(TEXT("MainFrame"));
    
      if (MainFrameModule.GetParentWindow().IsValid())
      {
        FSlateApplication::Get().AddWindowAsNativeChild(CookbookWindow, MainFrameModule.GetParentWindow().ToSharedRef());
      }
      else
      {
        FSlateApplication::Get().AddWindow(CookbookWindow);
      }
    };
  5. Within your editor module, add the following code to the StartupModule() function:
    IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
    
    auto Actions =MakeShareable(new FMyCustomAssetActions);
    AssetTools.RegisterAssetTypeActions(Actions);
    CreatedAssetTypeActions.Add(Actions);
  6. Add the following inside the module's ShutdownModule() function:
    IAssetTools& AssetTools = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools").Get();
    
    for (auto Action : CreatedAssetTypeActions)
    {
      AssetTools.UnregisterAssetTypeActions(Action.ToSharedRef());
    }
  7. Compile your project, and launch the editor.
  8. Create an instance of your custom Asset inside Content Browser.
  9. Right-click on your new Asset to see our custom command in the context menu.
    How to do it…
  10. Select the CustomAssetAction command to display a new blank editor window.

How it works…

  1. The base class for all asset type-specific context menu commands is FAssetTypeActions_Base, so we need to inherit from that class.
  2. FAssetTypeActions_Base is an abstract class that defines a number of virtual functions that allow for extending the context menu. The interface which contains the original information for these virtual functions can be found in IAssetTypeActions.h.
  3. We also declare a function which we bind to our custom context menu entry.
  4. IAssetTypeActions::HasActions ( const TArray<UObject*>& InObjects ) is the function called by the engine code to see if our AssetTypeActions class contains any actions that can be applied to the selected objects.
  5. IAssetTypeActions::GetActions(const TArray<UObject*>& InObjects, class FMenuBuilder& MenuBuilder) is called if the HasActions function returns true. It calls functions on MenuBuilder to create the menu options for the actions that we provide.
  6. IAssetTypeActions::GetName() returns the name of this class.
  7. IAssetTypeActions::GetSupportedClass() returns an instance of UClass which our actions class supports.
  8. IAssetTypeActions::GetTypeColor() returns the color associated with this class and actions.
  9. IAssetTypeActions::GetCategories() returns a category appropriate for the asset. This is used to change the category under which the actions show in the context menu.
  10. Our overridden implementation of HasActions simply returns true under all circumstances relying on filtering based on the results of GetSupportedClass.
  11. Inside the implementation of GetActions, we can call some functions on the MenuBuilder object that we are given as a function parameter. The MenuBuilder is passed as a reference, so any changes that are made by our function will persist after it returns.
  12. AddMenuEntry has a number of parameters. The first parameter is the name of the action itself. This is the name that will be visible within the context menu. The name is an FText so that it can be localized should you wish. For the sake of simplicity, we construct FText from a string literal and don't concern ourselves with multiple language support.
  13. The second parameter is also FText, which we construct by calling FText::FromString. This parameter is the text displayed on a tooltip if the user hovers over our command for more than a small amount of time.
  14. The next parameter is FSlateIcon for the command, which is constructed from the LevelEditor.ViewOptions icon within the editor style set.
  15. The last parameter to this function is an FUIAction instance. The FUIAction is a wrapper around a delegate binding, so we use FExecuteAction::CreateRaw to bind the command to the MyCustomAsset_Clicked function on this very instance of FMyCustomAssetActions.
  16. This means that when the menu entry is clicked, our MyCustomAssetContext_Clicked function will be run.
  17. Our implementation of GetName returns the name of our Asset type. This string will be used on the thumbnail for our Asset if we don't set one ourselves, apart from being used in the title of the menu section that our custom Assets will be placed in.
  18. As you'd expect, the implementation of GetSupportedClass returns UMyCustomAsset::StaticClass(), as this is the Asset type we want our actions to operate on.
  19. GetTypeColor() returns the color that will be used for color coding in Content Browser—the color is used in the bar at the bottom of the asset thumbnail. I've used Emerald here, but any arbitrary color will work.
  20. The real workhorse of this recipe is the MyCustomAssetContext_Clicked() function.
  21. The first thing that this function does is create a new instance of SWindow.
  22. SWindow is the Slate Window—a class from the Slate UI framework.
  23. Slate Widgets are created using the SNew function, which returns an instance of the widget requested.
  24. Slate uses the builder design pattern, which means that all the functions that are chained after SNew returns a reference to the object that was being operated on.
  25. In this function, we create our new SWindow, then set the window title, its client size or area, and whether it can be maximized or minimized.
  26. With our new Window ready, we need to get a reference to the root window for the editor so we can add our window to the hierarchy and get it displayed.
  27. We do this using the IMainFrameModule class. It's a module, so we use the Module Manager to load it.
  28. LoadModuleChecked will assert if we can't load the module, so we don't need to check it.
  29. If the module was loaded, we check that we have a valid parent window. If that window is valid, then we use FSlateApplication::AddWindowAsNativeChild to add our window as a child of the top-level parent window.
  30. If we don't have a top-level parent, the function uses AddWindow to add the new window without parenting it to another window within the hierarchy.
  31. So now we have a class which will display custom actions on our custom Asset type, but we need to actually tell the engine that it should ask our class to handle custom actions for the type. In order to do that, we need to register our class with the Asset Tools module.
  32. The best way to do this is to register our class when our editor module is loaded, and unregister it when it is shut down.
  33. As a result, we place our code into the StartupModule and ShutdownModule functions.
  34. Inside StartupModule, we load the Asset Tools module using Module Manager.
  35. With the module loaded, we create a new shared pointer that references an instance of our custom Asset actions class.
  36. All we then need to do is call AssetModule.RegisterAssetTypeActions, and pass in an instance of our actions class.
  37. We then need to store a reference to that Actions instance so that we can unregister it later.
  38. The sample code for this recipe uses an array of all the created asset actions in case we want to add custom actions for other classes as well.
  39. Within ShutdownModule, we again retrieve an instance of the Asset Tools module.
  40. Using a range-based for loop, we iterate over the array of Actions instances that we populated earlier, and call UnregisterAssetTypeActions, passing in our Actions class so it can be unregistered.
  41. With our class registered, the editor has been instructed to ask our registered class if it can handle assets which are right-clicked on.
  42. If the asset is of the Custom Asset class, then its StaticClass will match the one returned by GetSupportedClass. The editor will then call GetActions, and display the menu with the alterations made by our implementation of that function.
  43. When the CustomAssetAction button is clicked, our custom MyCustomAssetContext_Clicked function will be called via the delegate that we created.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.9.254