Skip to content

Commit

Permalink
Feature: add display of important subsystem subobjects in browser panel:
Browse files Browse the repository at this point in the history
By using meta specifier SBGetSubobjects pointing to a callable UFUNCTION plugin will gather and display subobjects in details view as nested tree items.

This feature was added to ease viewing of assistant objects related to subsystem without doing details customization or an extra pointer to subobject.
  • Loading branch information
aquanox committed Feb 20, 2025
1 parent 7941a86 commit 144d483
Show file tree
Hide file tree
Showing 16 changed files with 345 additions and 90 deletions.
Binary file added Images/UE5-Subobjects.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Model/Column/SubsystemBrowserColumn_Name.h"

#include "SubsystemBrowserSettings.h"
#include "SubsystemBrowserStyle.h"
#include "UI/SubsystemTableItem.h"
#include "Widgets/Images/SImage.h"
#include "Widgets/Text/STextBlock.h"
Expand All @@ -21,6 +22,8 @@ FSubsystemDynamicColumn_Name::FSubsystemDynamicColumn_Name()

TSharedPtr<SWidget> FSubsystemDynamicColumn_Name::GenerateColumnWidget(TSharedRef<const ISubsystemTreeItem> Item, TSharedRef<SSubsystemTableItem> TableRow) const
{
const bool bHasIcon = Item->CanHaveChildren() && ExtractIcon(Item) != nullptr;

return SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
Expand All @@ -36,10 +39,10 @@ TSharedPtr<SWidget> FSubsystemDynamicColumn_Name::GenerateColumnWidget(TSharedRe
SNew(SBox)
.VAlign(VAlign_Center)
.HeightOverride(22)
.WidthOverride(Item->CanHaveChildren() ? 16.f : 7.f)
.WidthOverride(bHasIcon ? 16.f : 7.f)
[
SNew(SImage)
.Image(TableRow, &SSubsystemTableItem::GetItemIconBrush)
.Image(this, &FSubsystemDynamicColumn_Name::ExtractIcon, Item)
]
]

Expand All @@ -57,6 +60,32 @@ TSharedPtr<SWidget> FSubsystemDynamicColumn_Name::GenerateColumnWidget(TSharedRe
];
}

const FSlateBrush* FSubsystemDynamicColumn_Name::ExtractIcon(TSharedRef<const ISubsystemTreeItem> Item) const
{
switch (Item->GetType())
{
case ISubsystemTreeItem::EItemType::Category:
{
return FStyleHelper::GetBrush(Item->bExpanded
? FSubsystemBrowserStyle::FolderOpenName
: FSubsystemBrowserStyle::FolderClosedName);
}
case ISubsystemTreeItem::EItemType::Subsystem:
{
//if (Item->CanHaveChildren() && Item->GetNumChildren() > 0)
//{
// return FStyleHelper::GetBrush(Item->bExpanded
// ? FSubsystemBrowserStyle::FolderOpenName
// : FSubsystemBrowserStyle::FolderClosedName);
//}
return Item->GetIcon();
}
case ISubsystemTreeItem::EItemType::Object:
default:
return Item->GetIcon();
}
}

FText FSubsystemDynamicColumn_Name::ExtractText(TSharedRef<const ISubsystemTreeItem> Item) const
{
FFormatNamedArguments Args;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct SUBSYSTEMBROWSER_API FSubsystemDynamicColumn_Name : public FSubsystemDyna
virtual bool IsVisibleByDefault() const override { return true; }
virtual TSharedPtr<SWidget> GenerateColumnWidget(TSharedRef<const ISubsystemTreeItem> Item, TSharedRef<class SSubsystemTableItem> TableRow) const override;
virtual void PopulateSearchStrings(const ISubsystemTreeItem& Item, TArray<FString>& OutSearchStrings) const override;
virtual const FSlateBrush* ExtractIcon(TSharedRef<const ISubsystemTreeItem> Item) const;
virtual FText ExtractText(TSharedRef<const ISubsystemTreeItem> Item) const override;
virtual FText ExtractTooltipText(TSharedRef<const ISubsystemTreeItem> Item) const override { return FText::GetEmpty(); }
virtual FSlateColor ExtractColor(TSharedRef<const ISubsystemTreeItem> Item) const override;
Expand Down
69 changes: 57 additions & 12 deletions Source/SubsystemBrowser/Model/SubsystemBrowserDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,57 @@ void FSubsystemTreeCategoryItem::GenerateTooltip(FSubsystemTableItemTooltipBuild
TooltipBuilder.AddPrimary(LOCTEXT("SubsystemTooltipItem_NumSub", "Num Subsystems"), FText::AsNumber(Subsystems.Num()));
}

FSubsystemTreeSubsystemItem::FSubsystemTreeSubsystemItem()
{
}

FSubsystemTreeSubsystemItem::FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemModel> InModel, TSharedPtr<ISubsystemTreeItem> InParent, UObject* Instance)
FSubsystemTreeObjectItem::FSubsystemTreeObjectItem(TSharedRef<FSubsystemModel> InModel, TSharedPtr<ISubsystemTreeItem> InParent, UObject* Instance)
{
Model = InModel;
Parent = InParent;

check(Instance);
Subsystem = Instance;
Object = Instance;
ObjectClass = Instance->GetClass();
}

bool FSubsystemTreeObjectItem::IsSelected() const
{
return Model.IsValid() && Model->IsItemSelected(SharedThis(this));
}

bool FSubsystemTreeObjectItem::IsStale() const
{
return Object.IsStale() || ObjectClass.IsStale();
}

void FSubsystemTreeObjectItem::GenerateTooltip(class FSubsystemTableItemTooltipBuilder& TooltipBuilder) const
{
FName ClassName = ObjectClass->GetFName();
TooltipBuilder.AddPrimary(LOCTEXT("SubsystemTooltipItem_Class", "Class"), FText::FromName(ClassName));

FString ModuleName = FPackageName::GetShortName(ObjectClass->GetOuterUPackage()->GetName());
TooltipBuilder.AddPrimary(LOCTEXT("SubsystemTooltipItem_Module", "Module"), FText::FromString(ModuleName));
}

FSubsystemTreeItemID FSubsystemTreeObjectItem::GetID() const
{
if (Object.IsValid())
{
return Object->GetFName();
}
return FSubsystemTreeItemID();
}

FText FSubsystemTreeObjectItem::GetDisplayName() const
{
if (Object.IsValid())
{
return FText::FromName(Object->GetFName());
}
return FText::GetEmpty();
}

FSubsystemTreeSubsystemItem::FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemModel> InModel, TSharedPtr<ISubsystemTreeItem> InParent, UObject* Instance)
: FSubsystemTreeObjectItem(InModel, InParent, Instance)
{
UClass* const InClass = Instance->GetClass();
Class = InClass;

DisplayName = InClass->GetDisplayNameText();
ClassName = InClass->GetFName();
Expand Down Expand Up @@ -90,11 +127,9 @@ FSubsystemTreeSubsystemItem::FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemMo
{
UserTooltip = UserTooltipValue;
}
}

bool FSubsystemTreeSubsystemItem::IsSelected() const
{
return Model.IsValid() && Model->IsItemSelected(SharedThis(this));

bHasSubobjectPicker = FSubsystemBrowserUtils::GetMetadataHierarchical(InClass, FSubsystemBrowserUserMeta::MD_SBGetSubobjects).IsSet()
|| FSubsystemBrowserUtils::GetMetadataHierarchical(InClass, FSubsystemBrowserUserMeta::MD_SBAutoGetSubobjects).IsSet();
}

FText FSubsystemTreeSubsystemItem::GetDisplayName() const
Expand All @@ -111,6 +146,11 @@ bool FSubsystemTreeSubsystemItem::HasViewableElements() const
return false;
}

const FSlateBrush* FSubsystemTreeSubsystemItem::GetIcon() const
{
return nullptr;
}

void FSubsystemTreeSubsystemItem::GenerateTooltip(FSubsystemTableItemTooltipBuilder& TooltipBuilder) const
{
if (TooltipBuilder.IsInAdvancedMode())
Expand Down Expand Up @@ -315,4 +355,9 @@ void FSubsystemTreeSubsystemItem::GenerateContextMenu(UToolMenu* MenuBuilder) co
}
}

bool FSubsystemTreeSubsystemItem::CanHaveChildren() const
{
return USubsystemBrowserSettings::Get()->ShouldShowSubobjbects() && bHasSubobjectPicker;
}

#undef LOCTEXT_NAMESPACE
110 changes: 76 additions & 34 deletions Source/SubsystemBrowser/Model/SubsystemBrowserDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,58 @@
class FSubsystemModel;
struct ISubsystemTreeItem;
struct FSubsystemTreeSubsystemItem;
struct FSubsystemTreeObjectItem;
struct FSubsystemTreeCategoryItem;

using FSubsystemTreeItemID = FName;
using SubsystemTreeItemPtr = TSharedPtr<ISubsystemTreeItem>;
using SubsystemTreeItemConstPtr = TSharedPtr<const ISubsystemTreeItem>;

/*

/**
* Node base class for Subsystem TreeView
*/
struct SUBSYSTEMBROWSER_API ISubsystemTreeItem : public TSharedFromThis<ISubsystemTreeItem>
{
enum class EItemType
{
Category,
Object,
Subsystem
};

ISubsystemTreeItem() = default;
virtual ~ISubsystemTreeItem() = default;

virtual EItemType GetType() const = 0;
virtual FSubsystemTreeItemID GetID() const = 0;
virtual int32 GetSortOrder() const { return 0; }

TSharedPtr<FSubsystemModel> GetModel() const { return Model; }
SubsystemTreeItemPtr GetParent() const { return Parent; }

virtual bool CanHaveChildren() const { return false; }
virtual TArray<SubsystemTreeItemPtr> GetChildren() const { return Children; }
virtual const TArray<SubsystemTreeItemPtr>& GetChildren() const { return Children; }
virtual int32 GetNumChildren() const { return Children.Num(); }
virtual void RemoveAllChildren() { Children.Empty(); }
virtual bool IsSelected() const { return false; }

virtual UObject* GetObjectForDetails() const { return nullptr; }
virtual bool IsStale() const { return false; }
virtual bool IsConfigExportable() const { return false; }
virtual bool IsGameModule() const { return false; }
virtual bool IsPluginModule() const { return false; }
virtual bool HasViewableElements() const { return false; }

virtual FText GetDisplayName() const = 0;

virtual FSubsystemTreeSubsystemItem* GetAsSubsystemDescriptor() const { return nullptr; }
virtual FSubsystemTreeCategoryItem* GetAsCategoryDescriptor() const { return nullptr; }
virtual const FSubsystemTreeObjectItem* GetAsObjectDescriptor() const { return nullptr; }
virtual const FSubsystemTreeSubsystemItem* GetAsSubsystemDescriptor() const { return nullptr; }
virtual const FSubsystemTreeCategoryItem* GetAsCategoryDescriptor() const { return nullptr; }

virtual const FSlateBrush* GetIcon() const { return nullptr; }
virtual void GenerateTooltip(class FSubsystemTableItemTooltipBuilder& TooltipBuilder) const {}
virtual void GenerateContextMenu(class UToolMenu* MenuBuilder) const { }

public:
bool bExpanded = true;
bool bVisible = true;
bool bNeedsRefresh = true;
Expand All @@ -64,30 +76,78 @@ struct SUBSYSTEMBROWSER_API ISubsystemTreeItem : public TSharedFromThis<ISubsyst
/**
* Node representing a Subsystem Category in TreeView
*/
struct SUBSYSTEMBROWSER_API FSubsystemTreeCategoryItem final : public ISubsystemTreeItem
struct SUBSYSTEMBROWSER_API FSubsystemTreeCategoryItem : public ISubsystemTreeItem
{
TSharedPtr<FSubsystemCategory> Data;

FSubsystemTreeCategoryItem() = default;
FSubsystemTreeCategoryItem(TSharedRef<FSubsystemModel> InModel, TSharedRef<FSubsystemCategory> InCategory);

virtual EItemType GetType() const override { return EItemType::Category; }
virtual FSubsystemTreeItemID GetID() const override { return Data->Name; }
virtual int32 GetSortOrder() const override { return Data->SortOrder; }
virtual FText GetDisplayName() const override { return Data->Label; }
virtual bool CanHaveChildren() const override { return true; }
virtual FSubsystemTreeCategoryItem* GetAsCategoryDescriptor() const override { return const_cast<FSubsystemTreeCategoryItem*>(this); }
virtual void GenerateTooltip(class FSubsystemTableItemTooltipBuilder& TooltipBuilder) const override;
const FSubsystemCategory& GetData() const { check(Data.IsValid()); return *Data; }

virtual const FSubsystemTreeCategoryItem* GetAsCategoryDescriptor() const override { return this; }
public:
TSharedPtr<FSubsystemCategory> Data;
};

/**
* Node representing generic viewable object
*/
struct SUBSYSTEMBROWSER_API FSubsystemTreeObjectItem : public ISubsystemTreeItem
{
FSubsystemTreeObjectItem() = default;
FSubsystemTreeObjectItem(TSharedRef<FSubsystemModel> InModel, TSharedPtr<ISubsystemTreeItem> InParent, UObject* Instance);

virtual EItemType GetType() const override { return EItemType::Object; }
virtual FSubsystemTreeItemID GetID() const override;
virtual FText GetDisplayName() const override;
virtual UObject* GetObjectForDetails() const override { return Object.Get(); }
virtual bool IsSelected() const override;
virtual bool IsStale() const override;

virtual const FSubsystemTreeObjectItem* GetAsObjectDescriptor() const override { return this; }

//virtual const FSlateBrush* GetIcon() const override;
virtual void GenerateTooltip(class FSubsystemTableItemTooltipBuilder& TooltipBuilder) const override;
public:
//
TWeakObjectPtr<UObject> Object;
//
TWeakObjectPtr<UClass> ObjectClass;
};

/**
* Node representing a Subsystem in TreeView
*/
struct SUBSYSTEMBROWSER_API FSubsystemTreeSubsystemItem final : public ISubsystemTreeItem
struct SUBSYSTEMBROWSER_API FSubsystemTreeSubsystemItem : public FSubsystemTreeObjectItem
{
TWeakObjectPtr<UObject> Subsystem;
TWeakObjectPtr<UClass> Class;
FSubsystemTreeSubsystemItem() = default;
FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemModel> InModel, TSharedPtr<ISubsystemTreeItem> InParent, UObject* Instance);

virtual EItemType GetType() const override { return EItemType::Subsystem; }
virtual FSubsystemTreeItemID GetID() const override { return ClassName; }

virtual FText GetDisplayName() const override;

bool IsConfigExportable() const { return bConfigExportable; }
bool IsDefaultConfig() const { return bIsDefaultConfig; }
virtual bool IsGameModule() const override { return bIsGameModuleClass; }
virtual bool IsPluginModule() const override { return bIsPluginClass; }
virtual bool HasViewableElements() const override;

virtual const FSlateBrush* GetIcon() const override;
virtual void GenerateTooltip(class FSubsystemTableItemTooltipBuilder& TooltipBuilder) const override;
virtual void GenerateContextMenu(class UToolMenu* MenuBuilder) const override;

virtual bool CanHaveChildren() const override;

virtual const FSubsystemTreeSubsystemItem* GetAsSubsystemDescriptor() const override { return this; }

public:
// Friendly display name (Class Name)
FText DisplayName;
// Subsystem class name (ClassName)
Expand Down Expand Up @@ -124,25 +184,7 @@ struct SUBSYSTEMBROWSER_API FSubsystemTreeSubsystemItem final : public ISubsyste
bool bIsDefaultConfig = false;
bool bIsGameModuleClass = false;
bool bIsPluginClass = false;

FSubsystemTreeSubsystemItem();
FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemModel> InModel, TSharedPtr<ISubsystemTreeItem> InParent, UObject* Instance);

virtual FSubsystemTreeItemID GetID() const override { return ClassName; }
virtual bool IsSelected() const override;

virtual FText GetDisplayName() const override;

virtual FSubsystemTreeSubsystemItem* GetAsSubsystemDescriptor() const override { return const_cast<FSubsystemTreeSubsystemItem*>(this); }
virtual UObject* GetObjectForDetails() const override { return Subsystem.Get(); }
virtual bool IsStale() const override { return Subsystem.IsStale() || Class.IsStale(); }
virtual bool IsConfigExportable() const override { return bConfigExportable; }
bool IsDefaultConfig() const { return bIsDefaultConfig; }
virtual bool IsGameModule() const override { return bIsGameModuleClass; }
virtual bool IsPluginModule() const override { return bIsPluginClass; }
virtual bool HasViewableElements() const override;

virtual void GenerateTooltip(class FSubsystemTableItemTooltipBuilder& TooltipBuilder) const override;
virtual void GenerateContextMenu(class UToolMenu* MenuBuilder) const override;


bool bHasSubobjectPicker = false;
//TArray<TWeakObjectPtr<UObject>> SubobjectsToDisplay;
};
Loading

0 comments on commit 144d483

Please sign in to comment.