Skip to content

Commit

Permalink
New Feature: Subsystem Settings Panel #13
Browse files Browse the repository at this point in the history
- Adds a settings viewer for subsystems
- Automatically discovers Subsystems from Subsystem Categories
- Builtin engine subsystems can be edited with a custom Details View widget similar to standard one
- Additional custom meta tags for Settings: SBSettingsSection and SBSettingsSectionDesc

Additional changes:
- DetailsView filtering overhaul.
- When bForceShowHiddenProperties mode is enabled result can be filtered with two additional filters (any/config-only)
- bEditAnyProperty now has an additional filter for config

Known issues:
- Editing WorldSubsystem type that is present in current Editor World in any kind of DetailsView marks world modified and it is not possible to avoid it right now
  • Loading branch information
aquanox committed Jul 3, 2024
1 parent 494a2d2 commit b6b2f47
Show file tree
Hide file tree
Showing 38 changed files with 1,186 additions and 236 deletions.
Binary file added Images/UE5-SubsystemSettings.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 @@ -8,10 +8,16 @@
FSubsystemCategory_Editor::FSubsystemCategory_Editor()
{
Name = TEXT("EditorSubsystemCategory");
SettingsName = TEXT("Editor");
Label = NSLOCTEXT("SubsystemBrowser", "SubsystemBrowser_Editor", "Editor Subsystems");
SortOrder = 200;
}

UClass* FSubsystemCategory_Editor::GetSubsystemClass() const
{
return UEditorSubsystem::StaticClass();
}

void FSubsystemCategory_Editor::Select(UWorld* InContext, TArray<UObject*>& OutData) const
{
if (GEditor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
struct FSubsystemCategory_Editor : public FSubsystemCategory
{
FSubsystemCategory_Editor();
virtual UClass* GetSubsystemClass() const override;
virtual void Select(UWorld* InContext, TArray<UObject*>& OutData) const override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@
FSubsystemCategory_Engine::FSubsystemCategory_Engine()
{
Name = TEXT("EngineSubsystemCategory");
SettingsName = TEXT("Engine");
Label = NSLOCTEXT("SubsystemBrowser", "SubsystemBrowser_Engine", "Engine Subsystems");
SortOrder = 100;
}

UClass* FSubsystemCategory_Engine::GetSubsystemClass() const
{
return UEngineSubsystem::StaticClass();
}

void FSubsystemCategory_Engine::Select(UWorld* InContext, TArray<UObject*>& OutData) const
{
if (GEngine)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ struct FSubsystemCategory_Engine : public FSubsystemCategory
{
FSubsystemCategory_Engine();

virtual UClass* GetSubsystemClass() const override;
virtual void Select(UWorld* InContext, TArray<UObject*>& OutData) const override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@
FSubsystemCategory_GameInstance::FSubsystemCategory_GameInstance()
{
Name = TEXT("GameInstanceCategory");
SettingsName = TEXT("GameInstance");
Label = NSLOCTEXT("SubsystemBrowser", "SubsystemBrowser_GameInstance", "Game Instance Subsystems");
SortOrder = 300;
}

UClass* FSubsystemCategory_GameInstance::GetSubsystemClass() const
{
return UGameInstanceSubsystem::StaticClass();
}

void FSubsystemCategory_GameInstance::Select(UWorld* InContext, TArray<UObject*>& OutData) const
{
if (IsValid(InContext) && InContext->GetGameInstance())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
struct FSubsystemCategory_GameInstance : public FSubsystemCategory
{
FSubsystemCategory_GameInstance();
virtual UClass* GetSubsystemClass() const override;
virtual void Select(UWorld* InContext, TArray<UObject*>& OutData) const override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,16 @@
FSubsystemCategory_Player::FSubsystemCategory_Player()
{
Name = TEXT("PlayerCategory");
SettingsName = TEXT("LocalPlayer");
Label = NSLOCTEXT("SubsystemBrowser", "SubsystemBrowser_Player", "Player Subsystems");
SortOrder = 500;
}

UClass* FSubsystemCategory_Player::GetSubsystemClass() const
{
return ULocalPlayerSubsystem::StaticClass();
}

void FSubsystemCategory_Player::Select(UWorld* InContext, TArray<UObject*>& OutData) const
{
if (IsValid(InContext) && InContext->GetGameInstance())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
struct FSubsystemCategory_Player: public FSubsystemCategory
{
FSubsystemCategory_Player();
virtual UClass* GetSubsystemClass() const override;
virtual void Select(UWorld* InContext, TArray<UObject*>& OutData) const override;
};
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@
FSubsystemCategory_World::FSubsystemCategory_World()
{
Name = TEXT("WorldSubsystemCategory");
SettingsName = TEXT("World");
Label = NSLOCTEXT("SubsystemBrowser", "SubsystemBrowser_World", "World Subsystems");
SortOrder = 400;
}

UClass* FSubsystemCategory_World::GetSubsystemClass() const
{
return UWorldSubsystem::StaticClass();
}

void FSubsystemCategory_World::Select(UWorld* InContext, TArray<UObject*>& OutData) const
{
if (IsValid(InContext))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@
struct FSubsystemCategory_World : public FSubsystemCategory
{
FSubsystemCategory_World();
virtual UClass* GetSubsystemClass() const override;
virtual void Select(UWorld* InContext, TArray<UObject*>& OutData) const override;
};
8 changes: 7 additions & 1 deletion Source/SubsystemBrowser/Model/SubsystemBrowserCategory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@
#include "Model/SubsystemBrowserCategory.h"

#include "SubsystemBrowserFlags.h"
#include "Subsystems/Subsystem.h"

#define LOCTEXT_NAMESPACE "SubsystemBrowser"

FSubsystemCategory::FSubsystemCategory(const FName& Name, const FText& Label, int32 SortOrder)
: Name(Name), Label(Label), SortOrder(SortOrder)
: Name(Name), SettingsName(Name), Label(Label), SortOrder(SortOrder)
{
}

UClass* FSubsystemCategory::GetSubsystemClass() const
{
return USubsystem::StaticClass();
}

FSimpleSubsystemCategory::FSimpleSubsystemCategory(const FName& Name, const FText& Label, const FEnumSubsystemsDelegate& Selector, int32 SortOrder)
: FSubsystemCategory(Name, Label, SortOrder), Selector(Selector)
{
Expand Down
7 changes: 7 additions & 0 deletions Source/SubsystemBrowser/Model/SubsystemBrowserCategory.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ struct SUBSYSTEMBROWSER_API FSubsystemCategory : public TSharedFromThis<FSubsyst
{
/* Category config identifier */
FName Name;
/* Category display in Settings */
FName SettingsName;
/* Category display title */
FText Label;
/* Sort weight for the category (with 0 being topmost, 1000 bottom last) */
Expand All @@ -26,10 +28,15 @@ struct SUBSYSTEMBROWSER_API FSubsystemCategory : public TSharedFromThis<FSubsyst
virtual ~FSubsystemCategory() = default;

const FName& GetID() const { return Name; }
const FName& GetSettingsName() const { return SettingsName; }
const FText& GetDisplayName() const { return Label; }
int32 GetSortOrder() const { return SortOrder; }

virtual bool IsVisibleByDefault() const { return true; }
virtual bool IsVisibleInSettings() const { return true; }

/* Get primary subsystem category class */
virtual UClass* GetSubsystemClass() const;

/* Select subsystems for this category */
virtual void Select(UWorld* InContext, TArray<UObject*>& OutData) const = 0;
Expand Down
2 changes: 1 addition & 1 deletion Source/SubsystemBrowser/Model/SubsystemBrowserColumn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void FSubsystemDynamicTextColumn::SortItems(TArray<SubsystemTreeItemPtr>& RootIt

#undef LOCTEXT_NAMESPACE

#if ENABLE_SUBSYSTEM_BROWSER_EXAMPLES && SINCE_UE_VERSION(4, 27, 0)
#if ENABLE_SUBSYSTEM_BROWSER_EXAMPLES && !UE_VERSION_OLDER_THAN(4, 27, 0)

// 1. Create a new struct inheriting FSubsystemDynamicColumn

Expand Down
13 changes: 5 additions & 8 deletions Source/SubsystemBrowser/Model/SubsystemBrowserDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,13 @@ FSubsystemTreeSubsystemItem::FSubsystemTreeSubsystemItem(TSharedRef<FSubsystemMo
ModuleName = FPackageName::GetShortName(Package);
bIsGameModuleClass = false;
}

ScriptName = FString::Printf(TEXT("/Script/%s.%s"), *ModuleName, *ClassName.ToString());

if (InClass->HasAnyClassFlags(CLASS_Config) && !InClass->ClassConfigName.IsNone())
{
bConfigExportable = true;
bIsDefaultConfig = InClass->HasAnyClassFlags(CLASS_DefaultConfig);
bIsGlobalUserConfig = InClass->HasAnyClassFlags(CLASS_GlobalUserConfig);
ConfigName = InClass->ClassConfigName;
}

Expand Down Expand Up @@ -109,8 +108,6 @@ bool FSubsystemTreeSubsystemItem::HasViewableElements() const
return true;
if (PropertyStats.NumCallable)
return true;
if (PropertyStats.NumConfig)
return true;
return false;
}

Expand Down Expand Up @@ -263,11 +260,11 @@ void FSubsystemTreeSubsystemItem::GenerateContextMenu(UToolMenu* MenuBuilder) co
{
if (FSubsystemBrowserUtils::TryUpdateDefaultConfigFile(Self.Pin()->GetObjectForDetails()))
{
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowser", "Successfully updated defaults"), SNotificationItem::CS_Success);
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowserDefaultsUpdate_Success", "Successfully updated defaults"), SNotificationItem::CS_Success);
}
else
{
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowser", "Failed to update defaults"), SNotificationItem::CS_Fail);
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowserDefaultsUpdate_Failed", "Failed to update defaults"), SNotificationItem::CS_Fail);
}
}
}),
Expand All @@ -285,7 +282,7 @@ void FSubsystemTreeSubsystemItem::GenerateContextMenu(UToolMenu* MenuBuilder) co
{
FString ClipboardText = FSubsystemBrowserUtils::GenerateConfigExport(Self.Pin().Get(), true);
FSubsystemBrowserUtils::SetClipboardText(ClipboardText);
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowser", "Copied to clipboard"), SNotificationItem::CS_Success);
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowserClipboardCopy_Success", "Copied to clipboard"), SNotificationItem::CS_Success);
}
}),
FCanExecuteAction::CreateSP(this, &FSubsystemTreeSubsystemItem::IsConfigExportable)
Expand All @@ -302,7 +299,7 @@ void FSubsystemTreeSubsystemItem::GenerateContextMenu(UToolMenu* MenuBuilder) co
{
FString ClipboardText = FSubsystemBrowserUtils::GenerateConfigExport(Self.Pin().Get(), false);
FSubsystemBrowserUtils::SetClipboardText(ClipboardText);
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowser", "Copied to clipboard"), SNotificationItem::CS_Success);
FSubsystemBrowserUtils::ShowBrowserInfoMessage(LOCTEXT("SubsystemBrowserClipboardCopy_Success", "Copied to clipboard"), SNotificationItem::CS_Success);
}
}),
FCanExecuteAction::CreateSP(this, &FSubsystemTreeSubsystemItem::IsConfigExportable)
Expand Down
1 change: 0 additions & 1 deletion Source/SubsystemBrowser/Model/SubsystemBrowserDescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ struct SUBSYSTEMBROWSER_API FSubsystemTreeSubsystemItem final : public ISubsyste

bool bConfigExportable = false;
bool bIsDefaultConfig = false;
bool bIsGlobalUserConfig = false;
bool bIsGameModuleClass = false;
bool bIsPluginClass = false;

Expand Down
1 change: 1 addition & 0 deletions Source/SubsystemBrowser/SubsystemBrowser.Build.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public SubsystemBrowser(ReadOnlyTargetRules Target) : base(Target)
"WorldBrowser",
"LevelEditor",
"ToolMenus",
"SettingsEditor",
"AssetTools",
"Projects"
});
Expand Down
5 changes: 5 additions & 0 deletions Source/SubsystemBrowser/SubsystemBrowserFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,8 @@
* Toggle example code validation
*/
#define ENABLE_SUBSYSTEM_BROWSER_EXAMPLES 0

/**
*
*/
#define ENABLE_SUBSYSTEM_BROWSER_DEBUG_THINGS 0
59 changes: 21 additions & 38 deletions Source/SubsystemBrowser/SubsystemBrowserModule.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright 2022, Aquanox.

#include "SubsystemBrowserModule.h"

#include "SubsystemBrowserFlags.h"
#include "SubsystemBrowserSettings.h"
#include "SubsystemBrowserStyle.h"
Expand All @@ -15,10 +16,8 @@
#include "Model/Category/SubsystemBrowserCategory_World.h"
#include "UI/SubsystemBrowserPanel.h"
#include "ISettingsModule.h"
#include "ISettingsSection.h"
#include "Widgets/Docking/SDockTab.h"
#include "LevelEditor.h"
#include "ToolMenu.h"
#include "ToolMenus.h"
#include "WorkspaceMenuStructure.h"
#include "WorkspaceMenuStructureModule.h"
Expand All @@ -41,30 +40,20 @@ void FSubsystemBrowserModule::StartupModule()
{
FSubsystemBrowserStyle::Register();

USubsystemBrowserSettings* SettingsObject = USubsystemBrowserSettings::Get();

ISettingsModule& SettingsModule = FModuleManager::GetModuleChecked<ISettingsModule>("Settings");
SettingsSection = SettingsModule.RegisterSettings(
TEXT("Editor"), TEXT("Plugins"), TEXT("SubsystemBrowser"),
LOCTEXT("SubsystemBrowserSettingsName", "Subsystem Browser"),
LOCTEXT("SubsystemBrowserSettingsDescription", "Settings for Subsystem Browser Plugin"),
SettingsObject
);
SettingsSection->OnSelect().BindUObject(SettingsObject, &USubsystemBrowserSettings::OnSettingsSelected);
SettingsSection->OnResetDefaults().BindUObject(SettingsObject, &USubsystemBrowserSettings::OnSettingsReset);
SettingsManager.Register();

FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
LevelEditorModule.OnTabManagerChanged().AddLambda([]()
LevelEditorModule.OnTabManagerChanged().AddLambda([Module = this]()
{
FLevelEditorModule& LevelEditorModule = FModuleManager::GetModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
if (LevelEditorTabManager.IsValid())
{
LevelEditorTabManager->RegisterTabSpawner(SubsystemBrowserTabName, FOnSpawnTab::CreateStatic(&FSubsystemBrowserModule::HandleTabManagerSpawnTab))
LevelEditorTabManager->RegisterTabSpawner(SubsystemBrowserTabName, FOnSpawnTab::CreateRaw(Module, &FSubsystemBrowserModule::HandleSpawnBrowserTab))
.SetDisplayName(LOCTEXT("SubsystemBrowserTitle", "Subsystems"))
.SetTooltipText(LOCTEXT("SubsystemBrowserTooltip", "Open the Subsystem Browser tab."))
.SetGroup( WorkspaceMenu::GetMenuStructure().GetLevelEditorCategory() )
.SetIcon( FStyleHelper::GetSlateIcon(FSubsystemBrowserStyle::PanelIconName) );
.SetGroup(WorkspaceMenu::GetMenuStructure().GetLevelEditorCategory())
.SetIcon(FStyleHelper::GetSlateIcon(FSubsystemBrowserStyle::PanelIconName));
}
});

Expand All @@ -86,50 +75,36 @@ void FSubsystemBrowserModule::ShutdownModule()
LevelEditorModule->GetLevelEditorTabManager()->UnregisterTabSpawner(SubsystemBrowserTabName);
}

SettingsManager.Unregister();

FSubsystemBrowserStyle::UnRegister();
}
}

TSharedRef<SDockTab> FSubsystemBrowserModule::HandleTabManagerSpawnTab(const FSpawnTabArgs& Args)
TSharedRef<SDockTab> FSubsystemBrowserModule::HandleSpawnBrowserTab(const FSpawnTabArgs& Args)
{
UWorld* EditorWorld = GEditor ? GEditor->GetEditorWorldContext().World() : nullptr;

return SNew(SDockTab)
#if UE_VERSION_OLDER_THAN(5, 0, 0)
.Icon(FStyleHelper::GetBrush(FSubsystemBrowserStyle::PanelIconName))
#endif
.Label(LOCTEXT("SubsystemBrowserTitle", "Subsystems"))
[
SNew(SBorder)
//.Padding(4)
.BorderImage( FStyleHelper::GetBrush("ToolPanel.GroupBorder") )
.BorderImage( FStyleHelper::GetBrush(TEXT("ToolPanel.GroupBorder")) )
[
CreateSubsystemBrowser(Args)
SNew(SSubsystemBrowserPanel).InWorld(EditorWorld)
]
];
}

TSharedRef<SWidget> FSubsystemBrowserModule::CreateSubsystemBrowser(const FSpawnTabArgs& Args)
{
UWorld* EditorWorld = GEditor ? GEditor->GetEditorWorldContext().World() : nullptr;
return SNew(SSubsystemBrowserPanel).InWorld(EditorWorld);
}

void FSubsystemBrowserModule::SummonSubsystemTab()
{
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>(TEXT("LevelEditor"));
TSharedPtr<ILevelEditor> LevelEditorInstance = LevelEditorModule.GetLevelEditorInstance().Pin();
#if UE_VERSION_OLDER_THAN(4, 26, 0)
FGlobalTabmanager::Get()->InvokeTab(SubsystemBrowserTabName);
#else
FGlobalTabmanager::Get()->TryInvokeTab(SubsystemBrowserTabName);
#endif
}

void FSubsystemBrowserModule::SummonPluginSettingsTab()
{
ISettingsModule& Module = FModuleManager::GetModuleChecked<ISettingsModule>("Settings");
Module.ShowViewer(TEXT("Editor"), TEXT("Plugins"), TEXT("SubsystemBrowser"));
}

const TArray<SubsystemCategoryPtr>& FSubsystemBrowserModule::GetCategories() const
{
return Categories;
Expand Down Expand Up @@ -180,6 +155,14 @@ void FSubsystemBrowserModule::RegisterCategory(TSharedRef<FSubsystemCategory> In
}

Categories.Add(InCategory);

// Sort categories according to their order
Categories.Sort([](const SubsystemCategoryPtr& A, const SubsystemCategoryPtr& B)
{
return A->GetSortOrder() < B->GetSortOrder();
});

SettingsManager.HandleCategoriesChanged();
}

void FSubsystemBrowserModule::RemoveCategory(FName CategoryName)
Expand Down
Loading

0 comments on commit b6b2f47

Please sign in to comment.