Inspecting types with custom Details panels

By default, UObject-derived UAssets open in the generic property editor. It looks like the following screenshot:

Inspecting types with custom Details panels

However, at times you may wish for custom widgets to allow editing of properties on your class. To facilitate this, Unreal supports Details Customization, which is the focus of this recipe.

How to do it...

  1. Create a new header file called MyCustomAssetDetailsCustomization.h.
  2. Add the following includes to the header:
    #include "MyCustomAsset.h"
    #include "DetailLayoutBuilder.h"
    #include "IDetailCustomization.h"
    #include "IPropertyTypeCustomization.h"
  3. Define our customization class as follows:
    class FMyCustomAssetDetailsCustomization : public IDetailCustomization
    {
      public:
      virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
      void ColorPicked(FLinearColor SelectedColor);
      static TSharedRef<IDetailCustomization> FMyCustomAssetDetailsCustomization::MakeInstance()
      {
        return MakeShareable(new FMyCustomAssetDetailsCustomization);
      }
      TWeakObjectPtr<class UMyCustomAsset> MyAsset;
    };
  4. In the implementation file, create an implementation for CustomizeDetails:
    void FMyCustomAssetDetailsCustomization::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
    {
      const TArray< TWeakObjectPtr<UObject>>& SelectedObjects = DetailBuilder.GetDetailsView().GetSelectedObjects();
      for (int32 ObjectIndex = 0; !MyAsset.IsValid() && ObjectIndex < SelectedObjects.Num(); ++ObjectIndex)
      {
        const TWeakObjectPtr<UObject>& CurrentObject = SelectedObjects[ObjectIndex];
        if (CurrentObject.IsValid())
        {
          MyAsset = Cast<UMyCustomAsset>(CurrentObject.Get());
        }
      }
      DetailBuilder.EditCategory("CustomCategory", FText::GetEmpty(), ECategoryPriority::Important)
      .AddCustomRow(FText::GetEmpty())
      [
        SNew(SVerticalBox)
        + SVerticalBox::Slot()
        .VAlign(VAlign_Center)
        [
          SNew(SColorPicker)
          .OnColorCommitted(this, &FMyCustomAssetDetailsCustomization::ColorPicked)
        ]
      ];
    }
  5. Also create a definition for ColorPicked:
    void FMyCustomAssetDetailsCustomization::ColorPicked(FLinearColor SelectedColor)
    {
      if (MyAsset.IsValid())
      {
        MyAsset.Get()->ColorName = SelectedColor.ToFColor(false).ToHex();
      }
    }
  6. Lastly, add the following includes in the .cpp file:
    #include "UE4CookbookEditor.h"
    #include "IDetailsView.h"
    #include "DetailLayoutBuilder.h"
    #include "DetailCategoryBuilder.h"
    #include "SColorPicker.h"
    #include "SBoxPanel.h"
    #include "DetailWidgetRow.h"
    #include "MyCustomAssetDetailsCustomization.h"
  7. In our editor module header, add the following to the implementation of StartupModule:
    FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
    PropertyModule.RegisterCustomClassLayout(UMyCustomAsset::StaticClass()->GetFName(), FOnGetDetailCustomizationInstance::CreateStatic(&FMyCustomAssetDetailsCustomization::MakeInstance));
  8. Add the following to ShutdownModule:
    FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
    PropertyModule.UnregisterCustomClassLayout(UMyCustomAsset::StaticClass()->GetFName());
  9. Compile your code, and launch the editor. Create a new copy of MyCustomAsset via the content browser.
  10. Double-click on it to verify that the default editor now shows your custom layout:
    How to do it...

How it works...

  1. Details Customization is performed through the IDetailCustomization interface, which developers can inherit from when defining a class which customizes the way assets of a certain class are displayed.
  2. The main function that IDetailCustomization uses to allow for this process to occur is the following:
    virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
  3. Within our implementation of this function, we use methods on DetailBuilder passed in as a parameter to get an array of all selected objects. The loop then scans those to ensure that at least one selected object is of the correct type.
  4. Customizing the representation of a class is done by calling methods on the DetailBuilder object. We create a new category for our details view by using the EditCategory function.
  5. The first parameter of the EditCategory function is the name of the category we are going to manipulate.
  6. The second parameter is optional, and contains a potentially localized display name for the category.
  7. The third parameter is the priority of the category. Higher priority means it is displayed further up the list.
  8. EditCategory returns a reference to the category itself as CategoryBuilder, allowing us to chain additional method calls onto an invocation of EditCategory.
  9. As a result, we call AddCustomRow() on CategoryBuilder, which adds a new key-value pair to be displayed in the category.
  10. Using the Slate syntax, we then specify that the row will contain a Vertical Box with a single center-aligned slot.
  11. Inside the slot, we create a color picker control, and bind its OnColorCommitted delegate to our local ColorPicked event handler.
  12. Of course, this requires us to define and implement ColourPicked. It has the following signature:
    void FMyCustomAssetDetailsCustomization::ColorPicked(FLinearColor SelectedColor)
  13. Inside the implementation of ColorPicked, we check to see if one of our selected assets was of the correct type, because if at least one selected asset was correct, then MyAsset will be populated with a valid value.
  14. Assuming we have a valid asset, we set the ColorName property to the hex string value corresponding to the color selected by the user.
..................Content has been hidden....................

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