diff --git a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.dll b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.dll index 39022cf..35dbf0f 100644 Binary files a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.dll and b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.dll differ diff --git a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.pdb b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.pdb index b5f63b2..d3fd748 100644 Binary files a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.pdb and b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructor.pdb differ diff --git a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.dll b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.dll index 554fbe1..9ab1bb0 100644 Binary files a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.dll and b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.dll differ diff --git a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.pdb b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.pdb index 41a923e..5f102b3 100644 Binary files a/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.pdb and b/Binaries/Win64/UnrealEditor-SettingsWidgetConstructorEditor.pdb differ diff --git a/Binaries/Win64/UnrealEditor.modules b/Binaries/Win64/UnrealEditor.modules index f50e933..ff26493 100644 --- a/Binaries/Win64/UnrealEditor.modules +++ b/Binaries/Win64/UnrealEditor.modules @@ -1,5 +1,5 @@ { - "BuildId": "27405482", + "BuildId": "33043543", "Modules": { "SettingsWidgetConstructor": "UnrealEditor-SettingsWidgetConstructor.dll", diff --git a/Config/BaseSettingsWidgetConstructor.ini b/Config/BaseSettingsWidgetConstructor.ini index 6bc0ac6..fa20bfc 100644 --- a/Config/BaseSettingsWidgetConstructor.ini +++ b/Config/BaseSettingsWidgetConstructor.ini @@ -1,21 +1,23 @@ [/Script/SettingsWidgetConstructorEditor.SettingsWidgetFactory] -SettingsWidgetClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/WBP_SettingsWidgetConstructor.WBP_SettingsWidgetConstructor_C' +SettingsWidgetClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/WBP_SettingsWidgetConstructor.WBP_SettingsWidgetConstructor_C' [/Script/SettingsWidgetConstructor.SettingsDataAsset] SettingsDataTableInternal= SettingsDataRegistryInternal=/SettingsWidgetConstructor/Data/DR_SettingsDataTables.DR_SettingsDataTables -ButtonClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsButton.WBP_SettingsButton_C' -CheckboxClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsCheckBox.WBP_SettingsCheckBox_C' -ComboboxClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsCombobox.WBP_SettingsCombobox_C' -SliderClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsSlider.WBP_SettingsSlider_C' -TextLineClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsTextLine.WBP_SettingsTextLine_C' -UserInputClassInternal=WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsTextInput.WBP_SettingsTextInput_C' +ButtonClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsButton.WBP_SettingsButton_C' +CheckboxClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsCheckBox.WBP_SettingsCheckBox_C' +ComboboxClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsCombobox.WBP_SettingsCombobox_C' +SliderClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsSlider.WBP_SettingsSlider_C' +TextLineClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsTextLine.WBP_SettingsTextLine_C' +UserInputClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsTextInput.WBP_SettingsTextInput_C' +TooltipClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsToolTip.WBP_SettingsToolTip_C' +ColumnClassInternal=/Script/UMG.WidgetBlueprintGeneratedClass'/SettingsWidgetConstructor/Subwidgets/WBP_SettingsMenuColumn.WBP_SettingsMenuColumn_C' bAutoConstructInternal=True bAutoFocusOnOpenInternal=True SettingsPercentSizeInternal=(X=0.600000,Y=0.400000) SettingsPaddingInternal=(Left=50.000000,Top=50.000000,Right=50.000000,Bottom=50.000000) ScrollboxPercentHeightInternal=1.000000 -ScrollboxPaddingInternal=(Left=0.000000,Top=0.000000,Right=0.000000,Bottom=0.000000) +ColumnPaddingInternal=(Left=10.000000,Top=0.000000,Right=10.000000,Bottom=0.000000) SpaceBetweenColumnsInternal=10.000000 ButtonThemeDataInternal=(PressedPadding=(Left=0.000000,Top=0.000000,Right=0.000000,Bottom=0.000000),Texture=Texture2D'"/SettingsWidgetConstructor/Textures/T_Settings_Button.T_Settings_Button"',Size=(X=128.000000,Y=128.000000),DrawAs=Box,Margin=(Left=0.250000,Top=0.250000,Right=0.250000,Bottom=0.250000),Padding=(Left=0.000000,Top=0.000000,Right=0.000000,Bottom=0.000000)) CheckboxThemeDataInternal=(CheckedTexture=Texture2D'"/SettingsWidgetConstructor/Textures/T_Settings_Checkbox_checked.T_Settings_Checkbox_checked"',UndeterminedTexture=None,Texture=Texture2D'"/SettingsWidgetConstructor/Textures/T_Settings_Checkbox_unchecked.T_Settings_Checkbox_unchecked"',Size=(X=24.000000,Y=24.000000),DrawAs=Image,Margin=(Left=0.000000,Top=0.000000,Right=0.000000,Bottom=0.000000),Padding=(Left=0.000000,Top=0.000000,Right=0.000000,Bottom=0.000000)) diff --git a/Content/Subwidgets/WBP_SettingsButton.uasset b/Content/Subwidgets/WBP_SettingsButton.uasset index 622fd0c..d2c68b7 100644 Binary files a/Content/Subwidgets/WBP_SettingsButton.uasset and b/Content/Subwidgets/WBP_SettingsButton.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsCheckBox.uasset b/Content/Subwidgets/WBP_SettingsCheckBox.uasset index 47c8da2..d06a435 100644 Binary files a/Content/Subwidgets/WBP_SettingsCheckBox.uasset and b/Content/Subwidgets/WBP_SettingsCheckBox.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsCombobox.uasset b/Content/Subwidgets/WBP_SettingsCombobox.uasset index 83dadbd..3106cb0 100644 Binary files a/Content/Subwidgets/WBP_SettingsCombobox.uasset and b/Content/Subwidgets/WBP_SettingsCombobox.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsMenuColumn.uasset b/Content/Subwidgets/WBP_SettingsMenuColumn.uasset index b3ff83e..1610d06 100644 Binary files a/Content/Subwidgets/WBP_SettingsMenuColumn.uasset and b/Content/Subwidgets/WBP_SettingsMenuColumn.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsScrollItem.uasset b/Content/Subwidgets/WBP_SettingsScrollItem.uasset deleted file mode 100644 index 81446f0..0000000 Binary files a/Content/Subwidgets/WBP_SettingsScrollItem.uasset and /dev/null differ diff --git a/Content/Subwidgets/WBP_SettingsScrollWrapper.uasset b/Content/Subwidgets/WBP_SettingsScrollWrapper.uasset deleted file mode 100644 index 21a8cba..0000000 Binary files a/Content/Subwidgets/WBP_SettingsScrollWrapper.uasset and /dev/null differ diff --git a/Content/Subwidgets/WBP_SettingsScrollbox.uasset b/Content/Subwidgets/WBP_SettingsScrollbox.uasset deleted file mode 100644 index 67926a0..0000000 Binary files a/Content/Subwidgets/WBP_SettingsScrollbox.uasset and /dev/null differ diff --git a/Content/Subwidgets/WBP_SettingsSlider.uasset b/Content/Subwidgets/WBP_SettingsSlider.uasset index f1e6cfb..65f0986 100644 Binary files a/Content/Subwidgets/WBP_SettingsSlider.uasset and b/Content/Subwidgets/WBP_SettingsSlider.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsSpacer.uasset b/Content/Subwidgets/WBP_SettingsSpacer.uasset deleted file mode 100644 index c0f2a01..0000000 Binary files a/Content/Subwidgets/WBP_SettingsSpacer.uasset and /dev/null differ diff --git a/Content/Subwidgets/WBP_SettingsTextInput.uasset b/Content/Subwidgets/WBP_SettingsTextInput.uasset index 376e2bc..d728e1a 100644 Binary files a/Content/Subwidgets/WBP_SettingsTextInput.uasset and b/Content/Subwidgets/WBP_SettingsTextInput.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsTextLine.uasset b/Content/Subwidgets/WBP_SettingsTextLine.uasset index 91b6a46..60f5149 100644 Binary files a/Content/Subwidgets/WBP_SettingsTextLine.uasset and b/Content/Subwidgets/WBP_SettingsTextLine.uasset differ diff --git a/Content/Subwidgets/WBP_SettingsToolTip.uasset b/Content/Subwidgets/WBP_SettingsToolTip.uasset index cca2688..11250b3 100644 Binary files a/Content/Subwidgets/WBP_SettingsToolTip.uasset and b/Content/Subwidgets/WBP_SettingsToolTip.uasset differ diff --git a/Content/WBP_SettingsWidgetConstructor.uasset b/Content/WBP_SettingsWidgetConstructor.uasset index 13c2864..2b9de5b 100644 Binary files a/Content/WBP_SettingsWidgetConstructor.uasset and b/Content/WBP_SettingsWidgetConstructor.uasset differ diff --git a/README.md b/README.md index 0c38a12..1d0ebd6 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ Check out our [Release](https://github.com/JanSeliv/SettingsWidgetConstructor/re Also, explore this [game project repository](https://github.com/JanSeliv/Bomber) to view the Settings Widget Constructor in action. ## 📅 Changelog +#### 2024-12-26 +- Updated to **Unreal Engine 5.4**. +- Moved a significant chunk of the logic from blueprints to code and simplified amount of widgets used. #### 2023-10-12 - Updated to **Unreal Engine 5.3** - Added **multiple Settings Data Tables** support ([see doc](https://docs.google.com/document/d/1IXnOqrgaXTClP-0cIo28a9f6GHc9N1BCgTNnMk-X9VQ/edit#heading=h.cix3vjszb2vm)). diff --git a/SettingsWidgetConstructor.uplugin b/SettingsWidgetConstructor.uplugin index e315d22..61ada74 100644 --- a/SettingsWidgetConstructor.uplugin +++ b/SettingsWidgetConstructor.uplugin @@ -10,7 +10,7 @@ "DocsURL": "", "MarketplaceURL": "", "SupportURL": "mailto:janseliw@gmail.com", - "EngineVersion": "5.3.0", + "EngineVersion": "5.4.0", "EnabledByDefault": true, "CanContainContent": true, "IsBetaVersion": false, diff --git a/Source/SettingsWidgetConstructor/Private/Data/SettingArchetypesData.cpp b/Source/SettingsWidgetConstructor/Private/Data/SettingArchetypesData.cpp index 21c2781..4b9d632 100644 --- a/Source/SettingsWidgetConstructor/Private/Data/SettingArchetypesData.cpp +++ b/Source/SettingsWidgetConstructor/Private/Data/SettingArchetypesData.cpp @@ -31,12 +31,6 @@ void FSettingsButton::BindSetting(USettingsWidget& SettingsWidget, const FSettin SettingsWidget.BindButton(PrimaryData, *this); } -// Calls the Add function of the Settings Widget of this setting type -void FSettingsButton::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) -{ - SettingsWidget.AddButton(PrimaryData, *this); -} - /********************************************************************************************* * FSettingsCheckbox ********************************************************************************************* */ @@ -67,12 +61,6 @@ void FSettingsCheckbox::BindSetting(USettingsWidget& SettingsWidget, const FSett SettingsWidget.BindCheckbox(PrimaryData, *this); } -// Calls the Add function of the Settings Widget of this setting type -void FSettingsCheckbox::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) -{ - SettingsWidget.AddCheckbox(InOutPrimaryData, *this); -} - /********************************************************************************************* * FSettingsCombobox ********************************************************************************************* */ @@ -120,12 +108,6 @@ void FSettingsCombobox::BindSetting(USettingsWidget& SettingsWidget, const FSett SettingsWidget.BindCombobox(PrimaryData, *this); } -// Calls the Add function of the Settings Widget of this setting type -void FSettingsCombobox::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) -{ - SettingsWidget.AddCombobox(InOutPrimaryData, *this); -} - /********************************************************************************************* * FSettingsSlider ********************************************************************************************* */ @@ -156,12 +138,6 @@ void FSettingsSlider::BindSetting(USettingsWidget& SettingsWidget, const FSettin SettingsWidget.BindSlider(PrimaryData, *this); } -// Calls the Add function of the Settings Widget of this setting type -void FSettingsSlider::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) -{ - SettingsWidget.AddSlider(InOutPrimaryData, *this); -} - /********************************************************************************************* * FSettingsTextLine ********************************************************************************************* */ @@ -193,12 +169,6 @@ void FSettingsTextLine::BindSetting(USettingsWidget& SettingsWidget, const FSett SettingsWidget.BindTextLine(PrimaryData, *this); } -// Calls the Add function of the Settings Widget of this setting type -void FSettingsTextLine::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) -{ - SettingsWidget.AddTextLine(InOutPrimaryData, *this); -} - /********************************************************************************************* * FSettingsUserInput ********************************************************************************************* */ @@ -229,12 +199,6 @@ void FSettingsUserInput::BindSetting(USettingsWidget& SettingsWidget, const FSet SettingsWidget.BindUserInput(PrimaryData, *this); } -// Calls the Add function of the Settings Widget of this setting type -void FSettingsUserInput::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) -{ - SettingsWidget.AddUserInput(InOutPrimaryData, *this); -} - /********************************************************************************************* * FSettingsCustomWidget ********************************************************************************************* */ @@ -257,9 +221,3 @@ void FSettingsCustomWidget::BindSetting(USettingsWidget& SettingsWidget, const F { SettingsWidget.BindCustomWidget(PrimaryData, *this); } - -// Calls the Add function of the Settings Widget of this setting type -void FSettingsCustomWidget::AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) -{ - SettingsWidget.AddCustomWidget(InOutPrimaryData, *this); -} diff --git a/Source/SettingsWidgetConstructor/Private/Data/SettingsDataAsset.cpp b/Source/SettingsWidgetConstructor/Private/Data/SettingsDataAsset.cpp index 7eaceba..50e1c7e 100644 --- a/Source/SettingsWidgetConstructor/Private/Data/SettingsDataAsset.cpp +++ b/Source/SettingsWidgetConstructor/Private/Data/SettingsDataAsset.cpp @@ -5,6 +5,10 @@ #include "Data/SettingsDataTable.h" #include "MyUtilsLibraries/SettingsUtilsLibrary.h" //--- +#include "DataRegistry.h" +#include "Engine/Engine.h" +#include "Misc/CoreDelegates.h" +//--- #include UE_INLINE_GENERATED_CPP_BY_NAME(SettingsDataAsset) // Returns the data table, it has to be set manually @@ -14,7 +18,7 @@ const USettingsDataTable* USettingsDataAsset::GetSettingsDataTable() const } // Returns the Settings Data Registry asset, is automatically set by default to which 'Settings Data Table' is added by itself -const UDataRegistry* USettingsDataAsset::GetSettingsDataRegistry() const +UDataRegistry* USettingsDataAsset::GetSettingsDataRegistry() const { return SettingsDataRegistryInternal.LoadSynchronous(); } diff --git a/Source/SettingsWidgetConstructor/Private/Data/SettingsDataTable.cpp b/Source/SettingsWidgetConstructor/Private/Data/SettingsDataTable.cpp index eb98920..0aa9659 100644 --- a/Source/SettingsWidgetConstructor/Private/Data/SettingsDataTable.cpp +++ b/Source/SettingsWidgetConstructor/Private/Data/SettingsDataTable.cpp @@ -17,6 +17,12 @@ USettingsDataTable::USettingsDataTable() RowStruct = FSettingsRow::StaticStruct(); } +// Returns the table rows +void USettingsDataTable::GetSettingRows(TMap& OutRows) const +{ + GetRows(OutRows); +} + #if WITH_EDITOR // Called on every change in this data table to automatic set the key name by specified setting tag void USettingsDataTable::OnThisDataTableChanged(FName RowKey, const uint8& RowData) diff --git a/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SWCWidgetUtilsLibrary.h b/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SWCWidgetUtilsLibrary.h index dba6d8a..1114231 100644 --- a/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SWCWidgetUtilsLibrary.h +++ b/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SWCWidgetUtilsLibrary.h @@ -26,4 +26,9 @@ class FSWCWidgetUtilsLibrary * As an example, it returns SCheckbox slate widget from UCheckBox widget. */ template static FORCEINLINE TSharedPtr GetSlateWidget(const UWidget* ForWidget) { return ForWidget ? StaticCastSharedPtr(ForWidget->GetCachedWidget()) : nullptr; } + + /** Completely destroys specified widget. + * Is useful for MGF-modules unloading in runtime. + * In most gameplay cases it should not be used, since it's expensive: prefer collapse widget instead. */ + static void DestroyWidget(UUserWidget& ParentWidget); }; diff --git a/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SettingsUtilsLibrary.cpp b/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SettingsUtilsLibrary.cpp index aa92a7a..2a73d43 100644 --- a/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SettingsUtilsLibrary.cpp +++ b/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/SettingsUtilsLibrary.cpp @@ -30,7 +30,7 @@ UGameUserSettings* USettingsUtilsLibrary::GetGameUserSettings(const UObject* Opt } // Returns all Settings Rows from project's Settings Data Table and all other additional Data Tables from 'SettingsDataTable' Data Registry -void USettingsUtilsLibrary::GetAllSettingRows(TMap& OutSettingRows) +void USettingsUtilsLibrary::GenerateAllSettingRows(TMap& OutSettingRows) { if (!OutSettingRows.IsEmpty()) { @@ -102,7 +102,7 @@ void USettingsUtilsLibrary::GetAllSettingRows(TMap& OutSett for (const FSettingsRow& Row : OrderedSettings) { const FName Tag = Row.SettingsPicker.PrimaryData.Tag.GetTagName(); - OutSettingRows.Add(Tag, Row); + OutSettingRows.Add(Tag, Row.SettingsPicker); // Check if there's an override block for this tag const FSettingTag SettingTag = Row.SettingsPicker.PrimaryData.Tag; @@ -113,7 +113,7 @@ void USettingsUtilsLibrary::GetAllSettingRows(TMap& OutSett for (const FSettingsRow& OverrideRow : *OverrideBlock) { const FName OverrideTag = OverrideRow.SettingsPicker.PrimaryData.Tag.GetTagName(); - OutSettingRows.Add(OverrideTag, OverrideRow); + OutSettingRows.Add(OverrideTag, OverrideRow.SettingsPicker); } } } @@ -129,7 +129,7 @@ void USettingsUtilsLibrary::RegisterDataTable(const TSoftObjectPtr& SettingsDataRegistry = USettingsDataAsset::Get().GetSettingsDataRegistrySoft(); + const TSoftObjectPtr& SettingsDataRegistry = USettingsDataAsset::Get().GetSettingsDataRegistrySoft(); if (ensureMsgf(!SettingsDataRegistry.IsNull(), TEXT("ASSERT: 'SettingsDataRegistry' is null, it has to be set automatically, something went wrong!"))) { // Initialize the Settings Data Registry diff --git a/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/WidgetUtilsLibrary.cpp b/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/WidgetUtilsLibrary.cpp index bba0846..cb90599 100644 --- a/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/WidgetUtilsLibrary.cpp +++ b/Source/SettingsWidgetConstructor/Private/MyUtilsLibraries/WidgetUtilsLibrary.cpp @@ -40,6 +40,37 @@ UUserWidget* FSWCWidgetUtilsLibrary::FindWidgetOfClass(UObject* WorldContextObje { TArray FoundWidgets; UWidgetBlueprintLibrary::GetAllWidgetsOfClass(WorldContextObject, /*out*/FoundWidgets, ParentWidgetClass); - return !FoundWidgets.IsEmpty()? FoundWidgets[0] : nullptr; + return !FoundWidgets.IsEmpty() ? FoundWidgets[0] : nullptr; } +// Completely destroys specified widget +void FSWCWidgetUtilsLibrary::DestroyWidget(UUserWidget& ParentWidget) +{ + // Get an array of all child widgets + TArray ChildWidgets; + const UWidgetTree* WidgetTree = ParentWidget.WidgetTree; + WidgetTree->GetAllWidgets(ChildWidgets); + + // Iterate through the child widgets + for (UWidget* ChildWidgetIt : ChildWidgets) + { + UUserWidget* ChildUserWidget = Cast(ChildWidgetIt); + const UWidgetTree* WidgetTreeIt = IsValid(ChildUserWidget) ? ChildUserWidget->WidgetTree : nullptr; + const bool bHasChildWidgets = WidgetTreeIt && WidgetTreeIt->RootWidget; + + if (bHasChildWidgets) + { + // If the child widget has its own child widgets, recursively remove and destroy them + DestroyWidget(*ChildUserWidget); + } + } + + // Hide widget to let last chance react on visibility change + ParentWidget.SetVisibility(ESlateVisibility::Collapsed); + + // Remove the child widget from the viewport + ParentWidget.RemoveFromParent(); + + // RemoveFromParent() does not completely destroy widget, so schedule the child widget for destruction + ParentWidget.ConditionalBeginDestroy(); +} diff --git a/Source/SettingsWidgetConstructor/Private/SettingsWidgetConstructorModule.cpp b/Source/SettingsWidgetConstructor/Private/SettingsWidgetConstructorModule.cpp index 95e09e8..f8034d5 100644 --- a/Source/SettingsWidgetConstructor/Private/SettingsWidgetConstructorModule.cpp +++ b/Source/SettingsWidgetConstructor/Private/SettingsWidgetConstructorModule.cpp @@ -1,9 +1,8 @@ // Copyright (c) Yevhenii Selivanov. #include "SettingsWidgetConstructorModule.h" - -#define LOCTEXT_NAMESPACE "FSettingsWidgetConstructorModule" - +//--- +#include "Modules/ModuleManager.h" // Called right after the module DLL has been loaded and the module object has been created void FSettingsWidgetConstructorModule::StartupModule() { @@ -17,6 +16,4 @@ void FSettingsWidgetConstructorModule::ShutdownModule() // we call this function before unloading the module. } -#undef LOCTEXT_NAMESPACE - IMPLEMENT_MODULE(FSettingsWidgetConstructorModule, SettingsWidgetConstructor) diff --git a/Source/SettingsWidgetConstructor/Private/UI/SettingSubWidget.cpp b/Source/SettingsWidgetConstructor/Private/UI/SettingSubWidget.cpp index 536f4bd..0ba046c 100644 --- a/Source/SettingsWidgetConstructor/Private/UI/SettingSubWidget.cpp +++ b/Source/SettingsWidgetConstructor/Private/UI/SettingSubWidget.cpp @@ -2,6 +2,7 @@ #include "UI/SettingSubWidget.h" //--- +#include "Data/SettingsDataAsset.h" #include "MyUtilsLibraries/SWCWidgetUtilsLibrary.h" #include "UI/SettingsWidget.h" //--- @@ -9,11 +10,14 @@ #include "Components/CheckBox.h" #include "Components/ComboBoxString.h" #include "Components/EditableTextBox.h" +#include "Components/HorizontalBox.h" #include "Components/ScrollBox.h" #include "Components/SizeBox.h" #include "Components/Slider.h" #include "Components/TextBlock.h" +#include "Components/VerticalBox.h" #include "Widgets/Input/SButton.h" +#include "Widgets/Input/SCheckBox.h" #include "Widgets/Input/SComboBox.h" #include "Widgets/Input/SEditableTextBox.h" #include "Widgets/Input/SSlider.h" @@ -23,7 +27,7 @@ // Set the new setting tag for this widget void USettingSubWidget::SetSettingPrimaryRow(const FSettingsPrimary& InSettingPrimaryRow) { - SettingPrimaryRowInternal = InSettingPrimaryRow; + PrimaryDataInternal = InSettingPrimaryRow; } // Returns the main setting widget (the outer of this subwidget) @@ -51,6 +55,80 @@ void USettingSubWidget::SetSettingsWidget(USettingsWidget* InSettingsWidget) SettingsWidgetInternal = InSettingsWidget; } +// Sets the parent widget element in hierarchy of this subwidget +UPanelSlot* USettingSubWidget::Attach() +{ + if (ParentSlotInternal) + { + // is already attached + return ParentSlotInternal; + } + + const FSettingsDataBase* SettingData = GetSettingData(); + const EMyVerticalAlignment Alignment = SettingData ? SettingData->GetVerticalAlignment() : EMyVerticalAlignment::None; + if (!ensureMsgf(Alignment != EMyVerticalAlignment::None, TEXT("ASSERT: [%i] %s:\n'This widget '%s' can not be attached to the parent widget, because it has no alignment!"), __LINE__, *FString(__FUNCTION__), *GetName())) + { + return nullptr; + } + + UPanelWidget* ParentWidget = nullptr; + switch (Alignment) + { + case EMyVerticalAlignment::Header: + ParentWidget = GetSettingsWidgetChecked().GetHeaderVerticalBox(); + break; + case EMyVerticalAlignment::Content: + if (const USettingColumn* Column = GetSettingsWidgetChecked().GetColumnBySetting(GetSettingTag())) + { + ParentWidget = Column->GetVerticalHolderBox(); + } + break; + case EMyVerticalAlignment::Footer: + ParentWidget = GetSettingsWidgetChecked().GetFooterVerticalBox(); + break; + default: break; + } + + if (!ensureMsgf(ParentWidget, TEXT("ASSERT: [%i] %s:\n'ParentWidget' is not found for the setting '%s'"), __LINE__, *FString(__FUNCTION__), *GetSettingTag().ToString())) + { + return nullptr; + } + + ParentSlotInternal = ParentWidget->AddChild(this); + + ensureMsgf(ParentSlotInternal, TEXT("ASSERT: [%i] %s:\nFailed to attached the Setting subwidget with the next tag: '%s'"), __LINE__, *FString(__FUNCTION__), *GetSettingTag().ToString()); + return ParentSlotInternal; +} + +// Adds given widget as tooltip to this setting +void USettingSubWidget::AddTooltipWidget() +{ + if (PrimaryDataInternal.Tooltip.IsEmpty() + || PrimaryDataInternal.Tooltip.EqualToCaseIgnored(FCoreTexts::Get().None)) + { + return; + } + + USettingTooltip* CreatedWidget = CreateWidget(GetOwningPlayer(), USettingsDataAsset::Get().GetTooltipClass()); + checkf(CreatedWidget, TEXT("ERROR: [%i] %s:\n'CreatedWidget' is null!"), __LINE__, *FString(__FUNCTION__)); + + SetToolTip(CreatedWidget); + CreatedWidget->SetToolTipText(PrimaryDataInternal.Tooltip); + CreatedWidget->ApplyTheme(); +} + +// Base method that is called when the underlying slate widget is constructed +void USettingSubWidget::OnAddSetting(const FSettingsPicker& Setting) +{ + BPOnAddSetting(); + + AddTooltipWidget(); + + Attach(); + + ApplyTheme(); +} + // Returns the custom line height for this setting float USettingSubWidget::GetLineHeight() const { @@ -84,6 +162,12 @@ void USettingSubWidget::SetCaptionText(const FText& NewCaptionText) } } +// Set the new button setting data for this widget +void USettingButton::SetButtonData(const FSettingsButton& InButtonData) +{ + ButtonDataInternal = InButtonData; +} + // Called after the underlying slate widget is constructed void USettingButton::NativeConstruct() { @@ -99,6 +183,14 @@ void USettingButton::NativeConstruct() } } +// Is overridden to construct the button +void USettingButton::OnAddSetting(const FSettingsPicker& Setting) +{ + ButtonDataInternal = Setting.Button; + + Super::OnAddSetting(Setting); +} + // Called when the Button Widget is pressed void USettingButton::OnButtonPressed() { @@ -110,6 +202,12 @@ void USettingButton::OnButtonPressed() SettingsWidgetInternal->SetSettingButtonPressed(GetSettingTag()); } +// Set the new checkbox setting data for this widget +void USettingCheckbox::SetCheckboxData(const FSettingsCheckbox& InCheckboxData) +{ + CheckboxDataInternal = InCheckboxData; +} + // Called after the underlying slate widget is constructed void USettingCheckbox::NativeConstruct() { @@ -135,6 +233,20 @@ void USettingCheckbox::OnCheckStateChanged(bool bIsChecked) SettingsWidgetInternal->SetSettingCheckbox(GetSettingTag(), bIsChecked); } +// Is overridden to construct the checkbox +void USettingCheckbox::OnAddSetting(const FSettingsPicker& Setting) +{ + CheckboxDataInternal = Setting.Checkbox; + + Super::OnAddSetting(Setting); +} + +// Set the new combobox setting data for this widget +void USettingCombobox::SetComboboxData(const FSettingsCombobox& InComboboxData) +{ + ComboboxDataInternal = InComboboxData; +} + // Called after the underlying slate widget is constructed void USettingCombobox::NativeConstruct() { @@ -178,6 +290,20 @@ void USettingCombobox::OnMenuOpenChanged() } } +// Is overridden to construct the combobox +void USettingCombobox::OnAddSetting(const FSettingsPicker& Setting) +{ + ComboboxDataInternal = Setting.Combobox; + + Super::OnAddSetting(Setting); +} + +// Set the new slider setting data for this widget +void USettingSlider::SetSliderData(const FSettingsSlider& InSliderData) +{ + SliderDataInternal = InSliderData; +} + // Called when a new item is selected in the combobox void USettingCombobox::OnSelectionChanged(FString SelectedItem, ESelectInfo::Type SelectionType) { @@ -227,6 +353,28 @@ void USettingSlider::OnValueChanged(float Value) SettingsWidgetInternal->SetSettingSlider(GetSettingTag(), Value); } +// Is overridden to construct the slider +void USettingSlider::OnAddSetting(const FSettingsPicker& Setting) +{ + SliderDataInternal = Setting.Slider; + + Super::OnAddSetting(Setting); +} + +// Set the new Text Line setting data for this widget +void USettingTextLine::SetTextLineData(const FSettingsTextLine& InTextLineData) +{ + TextLineDataInternal = InTextLineData; +} + +// Is overridden to construct the text line +void USettingTextLine::OnAddSetting(const FSettingsPicker& Setting) +{ + TextLineDataInternal = Setting.TextLine; + + Super::OnAddSetting(Setting); +} + // Returns current text set in the Editable Text Box void USettingUserInput::GetEditableText(FText& OutText) const { @@ -248,6 +396,12 @@ void USettingUserInput::SetEditableText(const FText& InText) EditableTextBox->SetText(InText); } +// Set the new user input setting data for this widget +void USettingUserInput::SetUserInputData(const FSettingsUserInput& InUserInputData) +{ + UserInputDataInternal = InUserInputData; +} + // Called after the underlying slate widget is constructed void USettingUserInput::NativeConstruct() { @@ -274,11 +428,48 @@ void USettingUserInput::OnTextChanged(const FText& Text) SettingsWidgetInternal->SetSettingUserInput(GetSettingTag(), MewValue); } +// Is overridden to construct the user input +void USettingUserInput::OnAddSetting(const FSettingsPicker& Setting) +{ + UserInputDataInternal = Setting.UserInput; + + Super::OnAddSetting(Setting); +} + +// Set the new custom widget setting data for this widget +void USettingCustomWidget::SetCustomWidgetData(const FSettingsCustomWidget& InCustomWidgetData) +{ + CustomWidgetDataInternal = InCustomWidgetData; +} + +// Is overridden to construct the custom widget +void USettingCustomWidget::OnAddSetting(const FSettingsPicker& Setting) +{ + CustomWidgetDataInternal = Setting.CustomWidget; + + Super::OnAddSetting(Setting); +} + +// Is overridden to attach the column to the Settings Widget +UPanelSlot* USettingColumn::Attach() +{ + if (ParentSlotInternal) + { + // is already attached + return ParentSlotInternal; + } + + UHorizontalBox* ContentHorizontalBox = GetSettingsWidgetChecked().GetContentHorizontalBox(); + checkf(ContentHorizontalBox, TEXT("ERROR: [%i] %s:\n'ContentHorizontalBox' is null!"), __LINE__, *FString(__FUNCTION__)); + ParentSlotInternal = ContentHorizontalBox->AddChild(this); + return ParentSlotInternal; +} + // Called after the underlying slate widget is constructed -void USettingScrollBox::NativeConstruct() +void USettingColumn::NativeConstruct() { Super::NativeConstruct(); - + if (ScrollBoxWidget) { SlateScrollBoxInternal = FSWCWidgetUtilsLibrary::GetSlateWidget(ScrollBoxWidget); diff --git a/Source/SettingsWidgetConstructor/Private/UI/SettingsWidget.cpp b/Source/SettingsWidgetConstructor/Private/UI/SettingsWidget.cpp index e88dae0..4305913 100644 --- a/Source/SettingsWidgetConstructor/Private/UI/SettingsWidget.cpp +++ b/Source/SettingsWidgetConstructor/Private/UI/SettingsWidget.cpp @@ -4,10 +4,17 @@ //--- #include "Data/SettingsDataAsset.h" #include "MyUtilsLibraries/SettingsUtilsLibrary.h" +#include "MyUtilsLibraries/SWCWidgetUtilsLibrary.h" #include "UI/SettingSubWidget.h" //--- +#include "DataRegistry.h" +#include "DataRegistryTypes.h" #include "Blueprint/WidgetLayoutLibrary.h" #include "Components/SizeBox.h" +#include "Components/Viewport.h" +#include "Engine/Engine.h" +#include "Engine/GameViewportClient.h" +#include "Engine/Texture.h" #include "GameFramework/GameUserSettings.h" //--- #include UE_INLINE_GENERATED_CPP_BY_NAME(SettingsWidget) @@ -81,7 +88,7 @@ void USettingsWidget::ApplySettings() } // Update settings on UI -void USettingsWidget::UpdateSettings(const FGameplayTagContainer& SettingsToUpdate) +void USettingsWidget::UpdateSettings(const FGameplayTagContainer& SettingsToUpdate, bool bLoadFromConfig/* = false*/) { if (SettingsToUpdate.IsEmpty() || !SettingsToUpdate.IsValidIndex(0)) @@ -91,7 +98,7 @@ void USettingsWidget::UpdateSettings(const FGameplayTagContainer& SettingsToUpda if (SettingsTableRowsInternal.IsEmpty()) { - UpdateSettingsTableRows(); + CacheTable(); } for (const TTuple& RowIt : SettingsTableRowsInternal) @@ -105,7 +112,8 @@ void USettingsWidget::UpdateSettings(const FGameplayTagContainer& SettingsToUpda } FSettingsDataBase* ChosenData = Setting.GetChosenSettingsData(); - if (!ChosenData) + if (!ChosenData + || !ChosenData->CanUpdateSetting()) { continue; } @@ -116,8 +124,11 @@ void USettingsWidget::UpdateSettings(const FGameplayTagContainer& SettingsToUpda continue; } - // Obtain the latest value from configs and set it - Owner->LoadConfig(); + if (bLoadFromConfig) + { + // Obtain the latest value from configs and set it + Owner->LoadConfig(); + } FString Result; ChosenData->GetSettingValue(*this, SettingTag, /*Out*/Result); @@ -126,13 +137,13 @@ void USettingsWidget::UpdateSettings(const FGameplayTagContainer& SettingsToUpda } // Returns the name of found tag by specified function -const FSettingTag& USettingsWidget::GetTagByFunction(const FSettingFunctionPicker& FunctionPicker) const +const FSettingTag& USettingsWidget::GetTagByFunction(const FSettingFunctionPicker& SettingFunction) const { for (const TTuple& RowIt : SettingsTableRowsInternal) { const FSettingsPrimary& PrimaryData = RowIt.Value.PrimaryData; - if (PrimaryData.Getter == FunctionPicker - || PrimaryData.Setter == FunctionPicker) + if (PrimaryData.Getter == SettingFunction + || PrimaryData.Setter == SettingFunction) { return PrimaryData.Tag; } @@ -535,7 +546,7 @@ float USettingsWidget::GetScrollBoxHeight() const float Paddings = 0.f; const FMargin SettingsPadding = SettingsData.GetSettingsPadding(); Paddings += SettingsPadding.Top + SettingsPadding.Bottom; - const FMargin ScrollBoxPadding = SettingsData.GetScrollboxPadding(); + const FMargin ScrollBoxPadding = SettingsData.GetColumnPadding(); Paddings += ScrollBoxPadding.Top + ScrollBoxPadding.Bottom; const float ScrollBoxHeight = (SettingsSize - MarginsSize).Y - Paddings; @@ -594,7 +605,7 @@ void USettingsWidget::NativeConstruct() TryConstructSettings(); } - TryFocusOnUI(); + BindOnSettingsDataRegistryChanged(); } // Is called right after the game was started and windows size is set to construct settings @@ -617,7 +628,7 @@ void USettingsWidget::ConstructSettings() return; } - UpdateSettingsTableRows(); + CacheTable(); // BP implementation to cache some data before creating subwidgets OnConstructSettings(); @@ -631,33 +642,52 @@ void USettingsWidget::ConstructSettings() AddedSettings.AddTag(SettingRef.PrimaryData.Tag); } - UpdateSettings(AddedSettings); + UpdateSettings(AddedSettings, /*bLoadFromConfig*/true); UpdateScrollBoxesHeight(); } -void USettingsWidget::UpdateSettingsTableRows() +// Internal function to cache setting rows from Settings Data Table +void USettingsWidget::CacheTable() { - TMap SettingRows; - USettingsUtilsLibrary::GetAllSettingRows(/*Out*/SettingRows); + TMap SettingRows; + USettingsUtilsLibrary::GenerateAllSettingRows(/*Out*/SettingRows); if (!ensureMsgf(!SettingRows.IsEmpty(), TEXT("ASSERT: 'SettingRows' are empty"))) { return; } // Reset values if currently are set - OverallColumnsNumInternal = 1; SettingsTableRowsInternal.Empty(); - SettingsTableRowsInternal.Reserve(SettingRows.Num()); - for (const TTuple& SettingRowIt : SettingRows) + for (const TTuple& SettingRowIt : SettingRows) { - const FSettingsPicker& SettingsPicker = SettingRowIt.Value.SettingsPicker; + const FSettingsPicker& SettingsPicker = SettingRowIt.Value; SettingsTableRowsInternal.Emplace(SettingRowIt.Key, SettingsPicker); + } +} + +// Clears all added settings +void USettingsWidget::RemoveAllSettings() +{ + for (TTuple& RowIt : SettingsTableRowsInternal) + { + USettingSubWidget* SubWidget = RowIt.Value.PrimaryData.SettingSubWidget.Get(); + if (ensureMsgf(SubWidget, TEXT("ASSERT: [%i] %s:\n'SubWidget' is not valid!"), __LINE__, *FString(__FUNCTION__))) + { + FSWCWidgetUtilsLibrary::DestroyWidget(*SubWidget); + } + } + SettingsTableRowsInternal.Empty(); - // Set overall columns num by amount of rows that are marked to be started on next column - OverallColumnsNumInternal += static_cast(SettingsPicker.PrimaryData.bStartOnNextColumn); + for (USettingColumn* ColumnIt : ColumnsInternal) + { + if (ensureMsgf(ColumnIt, TEXT("ASSERT: [%i] %s:\n'ColumnIt' is not valid!"), __LINE__, *FString(__FUNCTION__))) + { + FSWCWidgetUtilsLibrary::DestroyWidget(*ColumnIt); + } } + ColumnsInternal.Empty(); } // Is called when In-Game menu became opened or closed @@ -735,22 +765,15 @@ USettingSubWidget* USettingsWidget::CreateSettingSubWidget(FSettingsPrimary& InO return SettingSubWidget; } -// Starts adding settings on the next column -void USettingsWidget::StartNextColumn_Implementation() -{ - // BP implementation - // ... -} - // Automatically sets the height for all scrollboxes in the Settings void USettingsWidget::UpdateScrollBoxesHeight() { ForceLayoutPrepass(); // Call it to make GetSettingsHeight work since it is called during widget construction const float ScrollBoxHeight = GetScrollBoxHeight(); - for (const USettingScrollBox* ScrollBoxIt : SettingScrollBoxesInternal) + for (const USettingColumn* ColumnIt : ColumnsInternal) { - USizeBox* SizeBoxWidget = ScrollBoxIt ? ScrollBoxIt->GetSizeBoxWidget() : nullptr; + USizeBox* SizeBoxWidget = ColumnIt ? ColumnIt->GetSizeBoxWidget() : nullptr; if (SizeBoxWidget) { SizeBoxWidget->SetMaxDesiredHeight(ScrollBoxHeight); @@ -897,22 +920,22 @@ bool USettingsWidget::BindSetting(FSettingsPicker& Setting) * @param SetterFunction The setter function to bind * @param AdditionalFunctionCalls Any additional function calls needed for specific widgets */ -#define BIND_SETTING(Primary, Data, GetterFunction, SetterFunction) \ - do \ - { \ - if (UObject* OwnerObject = Primary.GetSettingOwner(this)) \ - { \ - const FName GetterFunctionName = Primary.Getter.FunctionName; \ - if (Primary.OwnerFunctionList.Contains(GetterFunctionName)) \ - { \ - Data.GetterFunction.BindUFunction(OwnerObject, GetterFunctionName); \ - } \ - const FName SetterFunctionName = Primary.Setter.FunctionName; \ - if (Primary.OwnerFunctionList.Contains(SetterFunctionName)) \ - { \ - Data.SetterFunction.BindUFunction(OwnerObject, SetterFunctionName); \ - } \ - } \ +#define BIND_SETTING(Primary, Data, GetterFunction, SetterFunction) \ + do \ + { \ + if (UObject* OwnerObject = Primary.GetSettingOwner(this)) \ + { \ + const FName GetterFunctionName = Primary.Getter.FunctionName; \ + if (Primary.OwnerFunctionList.Contains(GetterFunctionName)) \ + { \ + Data.GetterFunction.BindUFunction(OwnerObject, GetterFunctionName); \ + } \ + const FName SetterFunctionName = Primary.Setter.FunctionName; \ + if (Primary.OwnerFunctionList.Contains(SetterFunctionName)) \ + { \ + Data.SetterFunction.BindUFunction(OwnerObject, SetterFunctionName); \ + } \ + } \ } while (0) // Bind button to own Get/Set delegates @@ -998,14 +1021,14 @@ void USettingsWidget::TryRebindDeferredContexts() { // Some settings were successfully rebound, remove them from the deferred list and update them DeferredBindingsInternal.RemoveTags(ReboundSettings); - UpdateSettings(ReboundSettings); + UpdateSettings(ReboundSettings, /*bLoadFromConfig*/true); } } // Add setting on UI. void USettingsWidget::AddSetting(FSettingsPicker& Setting) { - FSettingsDataBase* ChosenData = Setting.GetChosenSettingsData(); + const FSettingsDataBase* ChosenData = Setting.GetChosenSettingsData(); if (!ChosenData) { return; @@ -1015,9 +1038,81 @@ void USettingsWidget::AddSetting(FSettingsPicker& Setting) if (Setting.PrimaryData.bStartOnNextColumn) { - StartNextColumn(); + AddColumn(GetColumnIndexBySetting(PrimaryData.Tag)); } - CreateSettingSubWidget(PrimaryData, ChosenData->GetSubWidgetClass()); - ChosenData->AddSetting(*this, PrimaryData); + USettingSubWidget* SettingSubWidget = CreateSettingSubWidget(PrimaryData, ChosenData->GetSubWidgetClass()); + checkf(SettingSubWidget, TEXT("ERROR: [%i] %s:\n'SettingSubWidget' is null!"), __LINE__, *FString(__FUNCTION__)); + SettingSubWidget->OnAddSetting(Setting); +} + +/********************************************************************************************* + * Columns builder + ********************************************************************************************* */ + +// Returns the index of column for a Setting by specified tag or -1 if not found +int32 USettingsWidget::GetColumnIndexBySetting(const FSettingTag& SettingTag) const +{ + int32 ColumnIndex = 0; + for (const TTuple& RowIt : SettingsTableRowsInternal) + { + const FSettingsPrimary& PrimaryData = RowIt.Value.PrimaryData; + if (PrimaryData.bStartOnNextColumn) + { + ++ColumnIndex; + } + + if (PrimaryData.Tag == SettingTag) + { + return ColumnIndex; + } + } + + return INDEX_NONE; +} + +// Creates new column on specified index +void USettingsWidget::AddColumn(int32 ColumnIndex) +{ + USettingColumn* NewColumn = CreateWidget(this, USettingsDataAsset::Get().GetColumnClass()); + NewColumn->SetSettingsWidget(this); + ColumnIndex = FMath::Clamp(ColumnIndex, 0, ColumnsInternal.Num()); + ColumnsInternal.Insert(NewColumn, ColumnIndex); + NewColumn->OnAddSetting(FSettingsPicker()); +} + +/********************************************************************************************* + * Multiple Data Tables support + ********************************************************************************************* */ + +// Is called when the Settings Data Registry is changed +void USettingsWidget::OnSettingsDataRegistryChanged_Implementation(class UDataRegistry* SettingsDataRegistry) +{ + const UWorld* World = GetWorld(); + const APlayerController* PC = GetOwningPlayer(); + if (!World || World->bIsTearingDown + || !PC + || !IsInViewport() + || !SettingsDataRegistry || SettingsDataRegistry->GetLowestAvailability() == EDataRegistryAvailability::DoesNotExist) + { + // The game was ended or no data registry is set + return; + } + + // Perfectly, we should insert new settings here, + // But inserting anything in between to scrollbox is not supported by UE at all + // So, clear all settings first + RemoveAllSettings(); + ConstructSettings(); +} + +void USettingsWidget::BindOnSettingsDataRegistryChanged() +{ + UDataRegistry* SettingsDataRegistry = USettingsDataAsset::Get().GetSettingsDataRegistry(); + checkf(SettingsDataRegistry, TEXT("ERROR: [%i] %s:\n'SettingsDataRegistry' is not set in Project Settings!"), __LINE__, *FString(__FUNCTION__)); + FDataRegistryCacheVersionCallback& SettingsDataRegistryDelegate = SettingsDataRegistry->OnCacheVersionInvalidated(); + if (!SettingsDataRegistryDelegate.IsBoundToObject(this)) + { + SettingsDataRegistryDelegate.AddUObject(this, &ThisClass::OnSettingsDataRegistryChanged); + } } diff --git a/Source/SettingsWidgetConstructor/Public/Data/SettingArchetypesData.h b/Source/SettingsWidgetConstructor/Public/Data/SettingArchetypesData.h index 34f395d..bebf1ed 100644 --- a/Source/SettingsWidgetConstructor/Public/Data/SettingArchetypesData.h +++ b/Source/SettingsWidgetConstructor/Public/Data/SettingArchetypesData.h @@ -5,7 +5,9 @@ #include "Data/SettingTypes.h" //--- #include "Data/SettingFunction.h" +//--- #include "Framework/Text/TextLayout.h" +#include "Templates/SubclassOf.h" //--- #include "SettingArchetypesData.generated.h" @@ -46,7 +48,7 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsDataBase ********************************************************************************************* */ /** Base method to get the sub-widget class of this setting type. */ - virtual TSubclassOf GetSubWidgetClass() const PURE_VIRTUAL(FSettingsDataBase::GetSubWidgetClass, return nullptr;); + virtual TSubclassOf GetSubWidgetClass() const PURE_VIRTUAL(FSettingsDataBase::GetSubWidgetClass, return nullptr;); /** Base method to get the setting value, where appropriate Getter of Settings Widget will be called. */ virtual void GetSettingValue(const USettingsWidget& SettingsWidget, const FSettingTag& Tag, FString& OutResult) const PURE_VIRTUAL(FSettingsDataBase::GetSettingValue,); @@ -57,8 +59,11 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsDataBase /** Base method to Bind setting to specified in table Get/Set delegates, so both methods will be called. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) PURE_VIRTUAL(FSettingsDataBase::BindSetting,); - /** Base method to add the setting to the Settings Widget, where appropriate Add method of Settings Widget will be called. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) PURE_VIRTUAL(FSettingsDataBase::AddSetting,); + /** Returns true if the settings can be updated on opening the settings widget. */ + virtual FORCEINLINE bool CanUpdateSetting() const { return true; } + + /** Override this method to return header/footer/content used by the setting. Only some settings like button or text can be added to the margin area (header/footer). */ + virtual EMyVerticalAlignment GetVerticalAlignment() const { return EMyVerticalAlignment::Content; } }; /** @@ -105,8 +110,11 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsButton : public FSettingsDataBase /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; + /** Is overridden to prevent sending the button press events on opening the settings widget. */ + virtual FORCEINLINE bool CanUpdateSetting() const override { return false; } + + /** Is overriden to provide support to be added to any area (header/footer/content). */ + virtual EMyVerticalAlignment GetVerticalAlignment() const override { return VerticalAlignment; } }; /** @@ -151,9 +159,6 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsCheckbox : public FSettingsDataBas /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) override; }; /** @@ -220,9 +225,6 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsCombobox : public FSettingsDataBas /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) override; }; /** @@ -267,9 +269,6 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsSlider : public FSettingsDataBase /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) override; }; /** @@ -320,8 +319,8 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsTextLine : public FSettingsDataBas /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) override; + /** Is overriden to provide support to be added to any area (header/footer/content). */ + virtual EMyVerticalAlignment GetVerticalAlignment() const override { return VerticalAlignment; } }; /** @@ -371,9 +370,6 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsUserInput : public FSettingsDataBa /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) override; }; /** @@ -419,7 +415,4 @@ struct SETTINGSWIDGETCONSTRUCTOR_API FSettingsCustomWidget : public FSettingsDat /** Calls the Bind function of the Settings Widget of this setting type. */ virtual void BindSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& PrimaryData) override; - - /** Calls the Add function of the Settings Widget of this setting type. */ - virtual void AddSetting(USettingsWidget& SettingsWidget, const FSettingsPrimary& InOutPrimaryData) override; }; diff --git a/Source/SettingsWidgetConstructor/Public/Data/SettingsDataAsset.h b/Source/SettingsWidgetConstructor/Public/Data/SettingsDataAsset.h index b2b1b31..070576d 100644 --- a/Source/SettingsWidgetConstructor/Public/Data/SettingsDataAsset.h +++ b/Source/SettingsWidgetConstructor/Public/Data/SettingsDataAsset.h @@ -6,6 +6,8 @@ //--- #include "Data/SettingsThemeData.h" //--- +#include "Templates/SubclassOf.h" +//--- #include "SettingsDataAsset.generated.h" class USettingsDataTable; @@ -65,6 +67,14 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataAsset : public UDeveloperSettin UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") FORCEINLINE TSubclassOf GetUserInputClass() const { return UserInputClassInternal; } + /** Returns the tooltip class applied to each setting. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") + FORCEINLINE TSubclassOf GetTooltipClass() const { return TooltipClassInternal; } + + /** Returns the column class which holds scrollbox and sub-settings inside. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") + FORCEINLINE TSubclassOf GetColumnClass() const { return ColumnClassInternal; } + /** Returns true, when USettingsWidget::TryConstructSettings is automatically called whenever the Settings Widget becomes constructed (e.g: on UUserWidget::AddToViewport call). */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") FORCEINLINE bool IsAutoConstruct() const { return bAutoConstructInternal; } @@ -87,11 +97,7 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataAsset : public UDeveloperSettin /** Returns the padding of the scrollbox widget. */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") - const FORCEINLINE FMargin& GetScrollboxPadding() const { return ScrollboxPaddingInternal; } - - /** Return the padding space, used on adding next column. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") - FORCEINLINE float GetSpaceBetweenColumns() const { return SpaceBetweenColumnsInternal; } + const FORCEINLINE FMargin& GetColumnPadding() const { return ColumnPaddingInternal; } /** Return the button theme data. */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") @@ -119,8 +125,8 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataAsset : public UDeveloperSettin /** Returns the Settings Data Registry asset, is automatically set by default to which 'Settings Data Table' is added by itself. */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") - const UDataRegistry* GetSettingsDataRegistry() const; - const TSoftObjectPtr& GetSettingsDataRegistrySoft() const { return SettingsDataRegistryInternal; } + UDataRegistry* GetSettingsDataRegistry() const; + const TSoftObjectPtr& GetSettingsDataRegistrySoft() const { return SettingsDataRegistryInternal; } /********************************************************************************************* * Protected properties @@ -154,6 +160,14 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataAsset : public UDeveloperSettin UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "User Input Class", ShowOnlyInnerProperties)) TSubclassOf UserInputClassInternal; + /** The tooltip class applied to all settings, is config property. */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Tooltip Class", ShowOnlyInnerProperties)) + TSubclassOf TooltipClassInternal; + + /** The column class which holds scrollbox and sub-settings inside, is config property. */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Column Class", ShowOnlyInnerProperties)) + TSubclassOf ColumnClassInternal; + /** If true, it will automatically call USettingsWidget::TryConstructSettings whenever the Settings Widget becomes constructed (e.g: on UUserWidget::AddToViewport call). */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Auto Construct", ShowOnlyInnerProperties)) bool bAutoConstructInternal; @@ -174,13 +188,9 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataAsset : public UDeveloperSettin UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Scrollbox Percent Height", ClampMin = "0", ClampMax = "1", ShowOnlyInnerProperties)) float ScrollboxPercentHeightInternal; - /** The padding of the scrollbox widget, is config property. */ + /** The padding of the Column, is config property. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Scrollbox Padding", ShowOnlyInnerProperties)) - FMargin ScrollboxPaddingInternal; - - /** The padding space, used on adding next column, is config property. */ - UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Space Between Columns", ShowOnlyInnerProperties)) - float SpaceBetweenColumnsInternal; + FMargin ColumnPaddingInternal; /** The button theme data, is config property. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Button Theme Data")) @@ -208,7 +218,7 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataAsset : public UDeveloperSettin /** The Settings Data Registry asset, is automatically set by default to which 'Settings Data Table' is added by itself. */ UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Config, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Settings Data Registry", ShowOnlyInnerProperties)) - TSoftObjectPtr SettingsDataRegistryInternal; + TSoftObjectPtr SettingsDataRegistryInternal; /********************************************************************************************* * Internal diff --git a/Source/SettingsWidgetConstructor/Public/Data/SettingsDataTable.h b/Source/SettingsWidgetConstructor/Public/Data/SettingsDataTable.h index 6fb6581..44fb391 100644 --- a/Source/SettingsWidgetConstructor/Public/Data/SettingsDataTable.h +++ b/Source/SettingsWidgetConstructor/Public/Data/SettingsDataTable.h @@ -22,7 +22,7 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsDataTable : public USWCMyDataTable /** Returns the table rows. * @see USettingsDataAsset::SettingsDataTableInternal */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") - void GetSettingRows(TMap& OutRows) const { GetRows(OutRows); } + void GetSettingRows(TMap& OutRows) const; protected: #if WITH_EDITOR diff --git a/Source/SettingsWidgetConstructor/Public/Data/SettingsThemeData.h b/Source/SettingsWidgetConstructor/Public/Data/SettingsThemeData.h index e4a07f8..a72b344 100644 --- a/Source/SettingsWidgetConstructor/Public/Data/SettingsThemeData.h +++ b/Source/SettingsWidgetConstructor/Public/Data/SettingsThemeData.h @@ -4,6 +4,9 @@ #include "Components/SlateWrapperTypes.h" //--- +#include "Fonts/SlateFontInfo.h" +#include "Styling/SlateBrush.h" +//--- #include "SettingsThemeData.generated.h" /* --- Settings Theme Data dependencies --- diff --git a/Source/SettingsWidgetConstructor/Public/MyUtilsLibraries/SettingsUtilsLibrary.h b/Source/SettingsWidgetConstructor/Public/MyUtilsLibraries/SettingsUtilsLibrary.h index d4340bb..f7f7de6 100644 --- a/Source/SettingsWidgetConstructor/Public/MyUtilsLibraries/SettingsUtilsLibrary.h +++ b/Source/SettingsWidgetConstructor/Public/MyUtilsLibraries/SettingsUtilsLibrary.h @@ -20,13 +20,13 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsUtilsLibrary : public UBlueprintFun static class USettingsWidget* GetSettingsWidget(const UObject* WorldContextObject); /** Returns the Game User Settings object. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor", meta = (WorldContext = "OptionalWorldContext")) + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor", meta = (WorldContext = "OptionalWorldContext", CallableWithoutWorldContext)) static class UGameUserSettings* GetGameUserSettings(const UObject* OptionalWorldContext = nullptr); /** Returns all Settings Rows from project's Settings Data Table and all other additional Data Tables from 'SettingsDataTable' Data Registry. * Note: Is expensive function, prefer to cache the result once! */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor") - static void GetAllSettingRows(TMap& OutSettingRows); + static void GenerateAllSettingRows(TMap& OutSettingRows); /********************************************************************************************* * Multiple Data Tables support diff --git a/Source/SettingsWidgetConstructor/Public/UI/SettingSubWidget.h b/Source/SettingsWidgetConstructor/Public/UI/SettingSubWidget.h index 7002545..4282d53 100644 --- a/Source/SettingsWidgetConstructor/Public/UI/SettingSubWidget.h +++ b/Source/SettingsWidgetConstructor/Public/UI/SettingSubWidget.h @@ -18,66 +18,104 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingSubWidget : public UUserWidget public: /** Returns the widget that shows the caption text of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class UTextBlock* GetCaptionWidget() const { return CaptionWidget; } /** Returns the Size Box widget . */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class USizeBox* GetSizeBoxWidget() const { return SizeBoxWidget; } /** Returns the custom line height for this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") float GetLineHeight() const; /** Set custom line height for this setting. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget") void SetLineHeight(float NewLineHeight); /** Returns the caption text that is shown on UI. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") void GetCaptionText(FText& OutCaptionText) const; /** Set the new caption text on UI for this widget. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (AutoCreateRefTerm = "NewCaptionText")) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "NewCaptionText")) void SetCaptionText(const FText& NewCaptionText); /** Returns the setting tag of this widget. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") - const FORCEINLINE FSettingTag& GetSettingTag() const { return SettingPrimaryRowInternal.Tag; } + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingTag& GetSettingTag() const { return PrimaryDataInternal.Tag; } /** Returns the setting primary row of this widget. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") - const FORCEINLINE FSettingsPrimary& GetSettingPrimaryRow() const { return SettingPrimaryRowInternal; } + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsPrimary& GetSettingPrimaryRow() const { return PrimaryDataInternal; } /** Set the new setting tag for this widget. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (AutoCreateRefTerm = "InSettingPrimaryRow")) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InSettingPrimaryRow")) void SetSettingPrimaryRow(const FSettingsPrimary& InSettingPrimaryRow); /** Returns the main setting widget (the outer of this subwidget). */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") - class USettingsWidget* GetSettingsWidget() const; + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + USettingsWidget* GetSettingsWidget() const; USettingsWidget& GetSettingsWidgetChecked() const; /** Sets the main settings widget for this subwidget. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget") void SetSettingsWidget(USettingsWidget* InSettingsWidget); + /** Returns parent widget element in hierarchy of this subwidget: it could be a header/footer vertical box or column. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + FORCEINLINE UPanelSlot* GetParentSlot() const { return ParentSlotInternal; } + + /** Adds given widget as tooltip to this setting. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget") + void AddTooltipWidget(); + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Base method that returns the setting data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const { return nullptr; } + + /** Base method that is called when the underlying slate widget is constructed. + * May be called multiple times due to adding and removing from the hierarchy. */ + UFUNCTION(BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, DisplayName = "On Add Setting")) + void BPOnAddSetting(); + virtual void OnAddSetting(const FSettingsPicker& Setting); + +protected: + /** Sets the parent widget element in hierarchy of this subwidget. + * @return The slot where this widget was added, or null if the add failed. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget") + virtual UPanelSlot* Attach(); + + /** Applies 'Style', paddings, colors, etc. */ + UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "SettingSubWidget|Theme") + void ApplyTheme(); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The Size Box widget. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr SizeBoxWidget = nullptr; /** The widget that shows the caption text of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr CaptionWidget = nullptr; /** The setting primary row of this widget. */ - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, DisplayName = "Setting Primary Row")) - FSettingsPrimary SettingPrimaryRowInternal = FSettingsPrimary::EmptyPrimary; + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Primary Data")) + FSettingsPrimary PrimaryDataInternal = FSettingsPrimary::EmptyPrimary; /** The main settings widget. */ - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, DisplayName = "Settings Widget")) - TObjectPtr SettingsWidgetInternal = nullptr; + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Settings Widget")) + TObjectPtr SettingsWidgetInternal = nullptr; + + /** The parent widget element in hierarchy of this subwidget: it could be a header/footer vertical box or column. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Panel Widget")) + TObjectPtr ParentSlotInternal = nullptr; }; /** @@ -90,27 +128,53 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingButton : public USettingSubWidget public: /** Returns the actual button widget of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class UButton* GetButtonWidget() const { return ButtonWidget; } /** Returns the slate button. */ FORCEINLINE TSharedPtr GetSlateButton() const { return SlateButtonInternal.Pin(); } + /** Returns the button setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsButton& GetButtonData() const { return ButtonDataInternal; } + + /** Set the new button setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InButtonData")) + void SetButtonData(const FSettingsButton& InButtonData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The slate button.*/ TWeakPtr SlateButtonInternal = nullptr; /** The actual button widget of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr ButtonWidget = nullptr; + /** The button setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Button Data")) + FSettingsButton ButtonDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the button data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &ButtonDataInternal; } + +protected: /** Called after the underlying slate widget is constructed. * May be called multiple times due to adding and removing from the hierarchy. */ virtual void NativeConstruct() override; + /** Is overridden to construct the button. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; + /** Called when the Button Widget is pressed. * @see USettingButton::OnSettingButtonPressed */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected)) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected)) void OnButtonPressed(); }; @@ -124,28 +188,54 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingCheckbox : public USettingSubWidget public: /** Returns the actual checkbox widget of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class UCheckBox* GetCheckboxWidget() const { return CheckboxWidget; } /** Returns the slate checkbox. */ FORCEINLINE TSharedPtr GetSlateCheckbox() const { return SlateCheckboxInternal.Pin(); } + /** Returns the checkbox setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsCheckbox& GetCheckboxData() const { return CheckboxDataInternal; } + + /** Set the new checkbox setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InCheckboxData")) + void SetCheckboxData(const FSettingsCheckbox& InCheckboxData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The slate checkbox.*/ TWeakPtr SlateCheckboxInternal = nullptr; /** The actual checkbox widget of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr CheckboxWidget = nullptr; + /** The checkbox setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Checkbox Data")) + FSettingsCheckbox CheckboxDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the checkbox data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &CheckboxDataInternal; } + +protected: /** Called after the underlying slate widget is constructed. * May be called multiple times due to adding and removing from the hierarchy. */ virtual void NativeConstruct() override; /** Called when the checked state has changed. * @see USettingCheckbox::CheckboxWidgetInternal */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected)) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected)) void OnCheckStateChanged(bool bIsChecked); + + /** Is overridden to construct the checkbox. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; }; template @@ -161,7 +251,7 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingCombobox : public USettingSubWidget public: /** Returns the actual combobox widget of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class UComboBoxString* GetComboboxWidget() const { return ComboboxWidget; } typedef SComboBox> SComboboxString; @@ -170,21 +260,44 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingCombobox : public USettingSubWidget FORCEINLINE TSharedPtr GetSlateCombobox() const { return SlateComboboxInternal.Pin(); } /** Returns true if combobox is opened. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE bool IsComboboxOpened() const { return bIsComboboxOpenedInternal; } + /** Returns the combobox setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsCombobox& GetComboboxData() const { return ComboboxDataInternal; } + + /** Set the new combobox setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InComboboxData")) + void SetComboboxData(const FSettingsCombobox& InComboboxData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The slate combobox.*/ TWeakPtr SlateComboboxInternal = nullptr; /** The actual combobox widget of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr ComboboxWidget = nullptr; /** Is true if combobox is currently opened in Settings. */ - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, DisplayName = "Is Combobox Opened")) + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Is Combobox Opened")) bool bIsComboboxOpenedInternal = false; + /** The combobox setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Combobox Data")) + FSettingsCombobox ComboboxDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the combobox data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &ComboboxDataInternal; } + +protected: /** Called after the underlying slate widget is constructed. * May be called multiple times due to adding and removing from the hierarchy. */ virtual void NativeConstruct() override; @@ -194,12 +307,15 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingCombobox : public USettingSubWidget /** Called when a new item is selected in the combobox * @see USettingCheckbox::ComboboxWidgetInternal */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected)) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected)) void OnSelectionChanged(FString SelectedItem, ESelectInfo::Type SelectionType); /** Called when the combobox is opened or closed. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected)) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected)) void OnMenuOpenChanged(); + + /** Is overridden to construct the combobox. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; }; /** @@ -212,32 +328,58 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingSlider : public USettingSubWidget public: /** Returns the actual slider widget of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class USlider* GetSliderWidget() const { return SliderWidget; } /** Returns the slate slider. */ FORCEINLINE TSharedPtr GetSlateSlider() const { return SlateSliderInternal.Pin(); } + /** Returns the slider setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsSlider& GetSliderData() const { return SliderDataInternal; } + + /** Set the new slider setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InSliderData")) + void SetSliderData(const FSettingsSlider& InSliderData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The slate slider.*/ TWeakPtr SlateSliderInternal = nullptr; /** The actual slider widget of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr SliderWidget = nullptr; + /** The slider setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Slider Data")) + FSettingsSlider SliderDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the slider data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &SliderDataInternal; } + +protected: /** Called after the underlying slate widget is constructed. * May be called multiple times due to adding and removing from the hierarchy. */ virtual void NativeConstruct() override; /** Invoked when the mouse is released and a capture ends. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected)) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected)) void OnMouseCaptureEnd(); /** Called when the value is changed by slider or typing. * @see USettingCheckbox::SliderWidgetInternal */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected)) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected)) void OnValueChanged(float Value); + + /** Is overridden to construct the slider. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; }; /** @@ -249,6 +391,32 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingTextLine : public USettingSubWidget GENERATED_BODY() public: + /** Returns the Text Line setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsTextLine& GetTextLineData() const { return TextLineDataInternal; } + + /** Set the new Text Line setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InTextLineData")) + void SetTextLineData(const FSettingsTextLine& InTextLineData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ +protected: + /** The text line setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Text Line Data")) + FSettingsTextLine TextLineDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the text line data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &TextLineDataInternal; } + +protected: + /** Is overridden to construct the text line. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; }; /** @@ -261,36 +429,62 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingUserInput : public USettingSubWidget public: /** Returns the actual Editable Text Box widget of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class UEditableTextBox* GetEditableTextBox() const { return EditableTextBox; } /** Returns current text set in the Editable Text Box. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") void GetEditableText(FText& OutText) const; /** Set new text programmatically instead of by the user. */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (AutoCreateRefTerm = "InText")) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InText")) void SetEditableText(const FText& InText); /** Returns the slate editable text box. */ FORCEINLINE TSharedPtr GetSlateEditableTextBox() const { return SlateEditableTextBoxInternal.Pin(); } + /** Returns the user input setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsUserInput& GetUserInputData() const { return UserInputDataInternal; } + + /** Set the new user input setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InUserInputData")) + void SetUserInputData(const FSettingsUserInput& InUserInputData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The slate editable text box.*/ TWeakPtr SlateEditableTextBoxInternal = nullptr; /** The actual Editable Text Box widget of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr EditableTextBox = nullptr; + /** The user input setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "User Input Data")) + FSettingsUserInput UserInputDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the user input data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &UserInputDataInternal; } + +protected: /** Called after the underlying slate widget is constructed. * May be called multiple times due to adding and removing from the hierarchy. */ virtual void NativeConstruct() override; /** Called whenever the text is changed programmatically or interactively by the user. * @see USettingCheckbox::EditableTextBoxInternal */ - UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, AutoCreateRefTerm = "Text")) + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (BlueprintProtected, AutoCreateRefTerm = "Text")) void OnTextChanged(const FText& Text); + + /** Is overridden to construct the user input. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; }; /** @@ -302,33 +496,88 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingCustomWidget : public USettingSubWid GENERATED_BODY() public: + /** Returns the custom widget setting data. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + const FORCEINLINE FSettingsCustomWidget& GetCustomWidgetData() const { return CustomWidgetDataInternal; } + + /** Set the new custom widget setting data for this widget. */ + UFUNCTION(BlueprintCallable, Category = "SettingSubWidget", meta = (AutoCreateRefTerm = "InCustomWidgetData")) + void SetCustomWidgetData(const FSettingsCustomWidget& InCustomWidgetData); + + /********************************************************************************************* + * Data + ********************************************************************************************* */ +protected: + /** The custom widget setting data. */ + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, DisplayName = "Custom Widget Data")) + FSettingsCustomWidget CustomWidgetDataInternal; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +public: + /** Is overridden to return the custom widget data of this widget. */ + virtual const FSettingsDataBase* GetSettingData() const override { return &CustomWidgetDataInternal; } + +protected: + /** Is overridden to construct the custom widget. */ + virtual void OnAddSetting(const FSettingsPicker& Setting) override; }; /** -* The sub-widget of the Scrollbox widget settings. +* Represents the column which holds scrollbox and sub-settings inside. */ UCLASS() -class SETTINGSWIDGETCONSTRUCTOR_API USettingScrollBox : public USettingSubWidget +class SETTINGSWIDGETCONSTRUCTOR_API USettingColumn : public USettingSubWidget { GENERATED_BODY() public: /** Returns the actual ScrollBox widget of this setting. */ - UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Sub-Widget") + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") FORCEINLINE class UScrollBox* GetScrollBoxWidget() const { return ScrollBoxWidget; } /** Returns the slate ScrollBox. */ FORCEINLINE TSharedPtr GetSlateScrollBox() const { return SlateScrollBoxInternal.Pin(); } + /** Returns the vertical box that holds all the settings in this column, is attached to the ScrollBox. */ + UFUNCTION(BlueprintPure, Category = "SettingSubWidget") + FORCEINLINE class UVerticalBox* GetVerticalHolderBox() const { return VerticalHolderBox; } + + /********************************************************************************************* + * Data + ********************************************************************************************* */ protected: /** The slate ScrollBox.*/ TWeakPtr SlateScrollBoxInternal = nullptr; /** The actual ScrollBox widget of this setting. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Sub-Widget", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) TObjectPtr ScrollBoxWidget = nullptr; + /** The vertical box that holds all the settings in this column, is attached to the ScrollBox. */ + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "SettingSubWidget", meta = (BlueprintProtected, BindWidget)) + TObjectPtr VerticalHolderBox = nullptr; + + /********************************************************************************************* + * Events and overrides + ********************************************************************************************* */ +protected: + /** Is overridden to attach the column to the Settings Widget. */ + virtual UPanelSlot* Attach() override; + /** Called after the underlying slate widget is constructed. * May be called multiple times due to adding and removing from the hierarchy. */ virtual void NativeConstruct() override; }; + +/** + * Represents the ToolTip widget that is shown when the mouse is over the setting. + */ +UCLASS() +class SETTINGSWIDGETCONSTRUCTOR_API USettingTooltip : public USettingSubWidget +{ + GENERATED_BODY() + +public: +}; diff --git a/Source/SettingsWidgetConstructor/Public/UI/SettingsWidget.h b/Source/SettingsWidgetConstructor/Public/UI/SettingsWidget.h index 592a017..182038d 100644 --- a/Source/SettingsWidgetConstructor/Public/UI/SettingsWidget.h +++ b/Source/SettingsWidgetConstructor/Public/UI/SettingsWidget.h @@ -61,7 +61,7 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget /** Returns true when this widget is fully constructed and ready to be used. */ UFUNCTION(BlueprintPure, Category = "C++") - FORCEINLINE bool IsSettingsWidgetConstructed() const { return SettingsTableRowsInternal.Num() > 0; } + FORCEINLINE bool IsSettingsWidgetConstructed() const { return !SettingsTableRowsInternal.IsEmpty(); } /** Is called to player sound effect on any setting click. */ UFUNCTION(BlueprintImplementableEvent, Category = "Settings Widget Constructor") @@ -91,10 +91,12 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget void ApplySettings(); /** Update settings on UI. - * @param SettingsToUpdate Contains tags of settings that are needed to update. */ + * @param SettingsToUpdate Contains tags of settings that are needed to update. + * @param bLoadFromConfig If true, then load settings from config file, otherwise just update UI. */ UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor", meta = (AutoCreateRefTerm = "SettingsToUpdate")) void UpdateSettings( - UPARAM(meta = (Categories = "Settings")) const FGameplayTagContainer& SettingsToUpdate); + UPARAM(meta = (Categories = "Settings")) const FGameplayTagContainer& SettingsToUpdate, + bool bLoadFromConfig = false); /** Returns the name of found tag by specified function. */ UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor", meta = (AutoCreateRefTerm = "SettingFunction")) @@ -213,7 +215,6 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Getters", meta = (AutoCreateRefTerm = "SettingTag")) class USettingSubWidget* GetSettingSubWidget(const FSettingTag& SettingTag) const; -protected: /* --------------------------------------------------- * Protected properties * --------------------------------------------------- */ @@ -222,37 +223,38 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Transient, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Settings Table Rows")) TMap SettingsTableRowsInternal; - /** The index of the current column. */ - UPROPERTY(VisibleDefaultsOnly, BlueprintReadWrite, Transient, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Current Column Index")) - int32 CurrentColumnIndexInternal = 0; - - /** Is set automatically on started by amount of rows that are marked to be started on next column. Settings have at least one column. */ - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Overall Columns Num")) - int32 OverallColumnsNumInternal = 1; - - /** Contains all setting scrollboxes added to columns. */ - UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Transient, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "Setting ScrollBoxes")) - TArray> SettingScrollBoxesInternal; - /** Contains all Setting tags that failed to bind their Getter/Setter functions on initial construct, so it's stored to be rebound later. * @see USettingsWidget::TryRebindDeferredContexts */ - UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "DeferredBindings")) + UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "Settings Widget Constructor", meta = (BlueprintProtected, DisplayName = "DeferredBindings")) FGameplayTagContainer DeferredBindingsInternal; /* --------------------------------------------------- * Bound widget properties * --------------------------------------------------- */ +public: + /** Returns the widget of the header section. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Widgets") + FORCEINLINE class UVerticalBox* GetHeaderVerticalBox() const { return HeaderVerticalBox; } + + /** Returns the widget of the content section. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Widgets") + FORCEINLINE class UHorizontalBox* GetContentHorizontalBox() const { return ContentHorizontalBox; } + + /** Returns the widget of the footer section. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Widgets") + FORCEINLINE class UVerticalBox* GetFooterVerticalBox() const { return FooterVerticalBox; } + protected: /** The section in the top margin of Settings, usually contains a title. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Widgets", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "Settings Widget Constructor|Widgets", meta = (BlueprintProtected, BindWidget)) TObjectPtr HeaderVerticalBox = nullptr; /** The main section in the middle of Settings, contains all in-game settings. */ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Widgets", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "Settings Widget Constructor|Widgets", meta = (BlueprintProtected, BindWidget)) TObjectPtr ContentHorizontalBox = nullptr; /** The section in the bottom margin of Settings, usually contains the Back button*/ - UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Settings Widget Constructor|Widgets", meta = (BlueprintProtected, BindWidget)) + UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Transient, AdvancedDisplay, Category = "Settings Widget Constructor|Widgets", meta = (BlueprintProtected, BindWidget)) TObjectPtr FooterVerticalBox = nullptr; /* --------------------------------------------------- @@ -273,16 +275,16 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget /** Internal function to cache setting rows from Settings Data Table. */ UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) - void UpdateSettingsTableRows(); + void CacheTable(); + + /** Clears all added settings. */ + UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) + void RemoveAllSettings(); /** Is called when In-Game menu became opened or closed. */ UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) void OnToggleSettings(bool bIsVisible); - /** Starts adding settings on the next column. */ - UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) - void StartNextColumn(); - /** Automatically sets the height for all scrollboxes in the Settings. */ UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) void UpdateScrollBoxesHeight(); @@ -334,42 +336,10 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) void TryRebindDeferredContexts(); - /* --------------------------------------------------- - * Add by setting types - * --------------------------------------------------- */ -public: /** Add setting on UI. */ UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected)) void AddSetting(UPARAM(ref)FSettingsPicker& Setting); - /** Add button on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddButton(const FSettingsPrimary& Primary, const FSettingsButton& Data); - - /** Add checkbox on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddCheckbox(const FSettingsPrimary& Primary, const FSettingsCheckbox& Data); - - /** Add combobox on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddCombobox(const FSettingsPrimary& Primary, const FSettingsCombobox& Data); - - /** Add slider on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddSlider(const FSettingsPrimary& Primary, const FSettingsSlider& Data); - - /** Add simple text on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddTextLine(const FSettingsPrimary& Primary, const FSettingsTextLine& Data); - - /** Add text input on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddUserInput(const FSettingsPrimary& Primary, const FSettingsUserInput& Data); - - /** Add custom widget on UI. */ - UFUNCTION(BlueprintCallable, BlueprintImplementableEvent, Category = "Settings Widget Constructor|Adders", meta = (BlueprintProtected, AutoCreateRefTerm = "Primary,Data")) - void AddCustomWidget(const FSettingsPrimary& Primary, const FSettingsCustomWidget& Data); - /* --------------------------------------------------- * Blueprint implementable setters * @@ -395,4 +365,39 @@ class SETTINGSWIDGETCONSTRUCTOR_API USettingsWidget : public UUserWidget /** Internal blueprint function to set new text for an input box. */ UFUNCTION(BlueprintImplementableEvent, Category = "Settings Widget Constructor|Setters", meta = (BlueprintProtected, AutoCreateRefTerm = "UserInputTag")) void SetUserInput(const FSettingTag& UserInputTag, FName InValue); + + /********************************************************************************************* + * Columns builder + ********************************************************************************************* */ +public: + /** Returns the index of column for a Setting by specified tag or -1 if not found. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Columns", meta = (AutoCreateRefTerm = "SettingTag")) + int32 GetColumnIndexBySetting(const FSettingTag& SettingTag) const; + + /** Returns a column by specified index. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Columns") + class USettingColumn* GetColumnByIndex(int32 ColumnIndex) const { return ColumnsInternal.IsValidIndex(ColumnIndex) ? ColumnsInternal[ColumnIndex] : nullptr; } + + /** Returns a column by specified setting tag. */ + UFUNCTION(BlueprintPure, Category = "Settings Widget Constructor|Columns", meta = (AutoCreateRefTerm = "SettingTag")) + FORCEINLINE USettingColumn* GetColumnBySetting(const FSettingTag& SettingTag) const { return GetColumnByIndex(GetColumnIndexBySetting(SettingTag)); } + +protected: + /** Contains all setting columns. */ + UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Transient, Category = "Settings Widget Constructor|Columns", meta = (BlueprintProtected, DisplayName = "Columns")) + TArray> ColumnsInternal; + +protected: + /** Creates new column on specified index. */ + UFUNCTION(BlueprintCallable, Category = "Settings Widget Constructor|Columns", meta = (BlueprintProtected)) + void AddColumn(int32 ColumnIndex); + + /********************************************************************************************* + * Multiple Data Tables support + ********************************************************************************************* */ +protected: + /** Is called when the Settings Data Registry is changed. */ + UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "Settings Widget Constructor", meta = (BlueprintProtected)) + void OnSettingsDataRegistryChanged(class UDataRegistry* SettingsDataRegistry); + void BindOnSettingsDataRegistryChanged(); }; diff --git a/Source/SettingsWidgetConstructorEditor/Private/FunctionPickerType/FunctionPickerCustomization.cpp b/Source/SettingsWidgetConstructorEditor/Private/FunctionPickerType/FunctionPickerCustomization.cpp index 489a2f7..a3ad58b 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/FunctionPickerType/FunctionPickerCustomization.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/FunctionPickerType/FunctionPickerCustomization.cpp @@ -3,6 +3,10 @@ #include "FunctionPickerType/FunctionPickerCustomization.h" //--- #include "Data/SettingFunction.h" +//--- +#include "PropertyEditorModule.h" +#include "PropertyHandle.h" +#include "Modules/ModuleManager.h" // The name of class to be customized: SettingFunctionPicker const FName FFunctionPickerCustomization::PropertyClassName = FSettingFunctionPicker::StaticStruct()->GetFName(); diff --git a/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyDataTable.cpp b/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyDataTable.cpp index 7e9bc83..f44e07e 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyDataTable.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyDataTable.cpp @@ -6,6 +6,8 @@ #include "DesktopPlatformModule.h" #include "ToolMenus.h" #include "EditorFramework/AssetImportData.h" +#include "Engine/DataTable.h" +#include "Framework/Application/SlateApplication.h" #include "Misc/FileHelper.h" #include "Misc/MessageDialog.h" @@ -39,7 +41,7 @@ bool USWCMyDataTableFactory::DoesSupportClass(UClass* Class) FText FAssetTypeActions_MyDataTable::GetName() const { - return NSLOCTEXT("AssetTypeActions", "AssetTypeActions_MyDataTable", "My Data Table"); + return LOCTEXT("AssetTypeActions_MyDataTable", "My Data Table"); } UClass* FAssetTypeActions_MyDataTable::GetSupportedClass() const @@ -143,7 +145,7 @@ void FAssetTypeActions_MyDataTable::ExecuteExportAsJSON(TArray((*ObjIt).Get()); + const UDataTable* DataTable = ObjIt ? Cast(ObjIt->Get()) : nullptr; if (DataTable) { const FText Title = FText::Format(LOCTEXT("DataTable_ExportJSONDialogTitle", "Export '{0}' as JSON..."), FText::FromString(*DataTable->GetName())); diff --git a/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyUserWidget.cpp b/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyUserWidget.cpp index d64bc46..68f6b9b 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyUserWidget.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/MyAssets/AssetTypeActions_MyUserWidget.cpp @@ -8,8 +8,7 @@ #include "Blueprint/WidgetTree.h" #include "Components/CanvasPanel.h" #include "Kismet2/KismetEditorUtilities.h" - -#define LOCTEXT_NAMESPACE "AssetTypeActions" +#include "Misc/MessageDialog.h" void USWCMyUserWidgetBlueprint::GetReparentingRules(TSet& AllowedChildrenOfClasses, TSet& DisallowedChildrenOfClasses) const { @@ -27,7 +26,7 @@ USWCMyUserWidgetFactory::USWCMyUserWidgetFactory() FText USWCMyUserWidgetFactory::GetDisplayName() const { - return LOCTEXT("MyUserWidget", "My User Widget"); + return NSLOCTEXT("AssetTypeActions", "MyUserWidget", "My User Widget"); } UObject* USWCMyUserWidgetFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn, FName CallingContext) @@ -100,9 +99,7 @@ void FAssetTypeActions_MyUserWidget::OpenAssetEditor(const TArray& InO } else { - FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("FailedToLoadWidgetBlueprint", "Widget Blueprint could not be loaded because it derives from an invalid class.\nCheck to make sure the parent class for this blueprint hasn't been removed!")); + FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("AssetTypeActions", "FailedToLoadWidgetBlueprint", "Widget Blueprint could not be loaded because it derives from an invalid class.\nCheck to make sure the parent class for this blueprint hasn't been removed!")); } } } - -#undef LOCTEXT_NAMESPACE diff --git a/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.cpp b/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.cpp index 40d8cb4..381d1e0 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.cpp @@ -1,13 +1,15 @@ // Copyright (c) Yevhenii Selivanov. #include "MyPropertyType/PropertyData.h" +//--- +#include "PropertyHandle.h" // Empty property data const FPropertyData FPropertyData::Empty = FPropertyData(); // Custom constructor, is not required, but fully init property data. FPropertyData::FPropertyData(TSharedRef InPropertyHandle) - : PropertyHandle(InPropertyHandle) + : PropertyHandle(MoveTemp(InPropertyHandle)) { PropertyName = GetPropertyNameFromHandle(); PropertyValue = GetPropertyValueFromHandle(); diff --git a/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.h b/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.h index 4740e8d..c43a7f1 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.h +++ b/Source/SettingsWidgetConstructorEditor/Private/MyPropertyType/PropertyData.h @@ -2,6 +2,10 @@ #pragma once +#include "CoreMinimal.h" +#include "Layout/Visibility.h" +#include "Misc/Attribute.h" + /** * Contains data that describes property. */ @@ -17,7 +21,7 @@ struct FPropertyData FPropertyData() = default; /** Custom constructor, is not required, but fully init property data. */ - explicit FPropertyData(TSharedRef InPropertyHandle); + explicit FPropertyData(TSharedRef InPropertyHandle); /** The name of a property. */ FName PropertyName = NAME_None; @@ -26,7 +30,7 @@ struct FPropertyData FName PropertyValue = NAME_None; /** The handle of a property. */ - TSharedPtr PropertyHandle = nullptr; + TSharedPtr PropertyHandle = nullptr; /** Determines if property is active (not greyed out). */ TAttribute bIsEnabled = true; diff --git a/Source/SettingsWidgetConstructorEditor/Private/SettingTagCustomization.cpp b/Source/SettingsWidgetConstructorEditor/Private/SettingTagCustomization.cpp index 9bce038..26d157e 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/SettingTagCustomization.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/SettingTagCustomization.cpp @@ -3,6 +3,8 @@ #include "SettingTagCustomization.h" //--- #include "Data/SettingTag.h" +//--- +#include "PropertyEditorModule.h" /** The name of class to be customized: SettingTag */ const FName FSettingTagCustomization::PropertyClassName = FSettingTag::StaticStruct()->GetFName(); diff --git a/Source/SettingsWidgetConstructorEditor/Private/SettingsPickerCustomization.cpp b/Source/SettingsWidgetConstructorEditor/Private/SettingsPickerCustomization.cpp index fa5b798..7a38b2d 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/SettingsPickerCustomization.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/SettingsPickerCustomization.cpp @@ -2,8 +2,12 @@ #include "SettingsPickerCustomization.h" //--- -#include "FunctionPickerType/FunctionPickerCustomization.h" #include "Data/SettingsRow.h" +#include "FunctionPickerType/FunctionPickerCustomization.h" +//--- +#include "PropertyEditorModule.h" +#include "PropertyHandle.h" +#include "Modules/ModuleManager.h" // The name of class to be customized: SettingsPicker const FName FSettingsPickerCustomization::PropertyClassName = FSettingsPicker::StaticStruct()->GetFName(); diff --git a/Source/SettingsWidgetConstructorEditor/Private/SettingsWidgetConstructorEditorModule.cpp b/Source/SettingsWidgetConstructorEditor/Private/SettingsWidgetConstructorEditorModule.cpp index bafee96..e35fe6f 100644 --- a/Source/SettingsWidgetConstructorEditor/Private/SettingsWidgetConstructorEditorModule.cpp +++ b/Source/SettingsWidgetConstructorEditor/Private/SettingsWidgetConstructorEditorModule.cpp @@ -11,8 +11,6 @@ #include "KismetCompiler.h" #include "Modules/ModuleManager.h" -#define LOCTEXT_NAMESPACE "FSettingsWidgetConstructorEditorModule" - // Called right after the module DLL has been loaded and the module object has been created void FSettingsWidgetConstructorEditorModule::StartupModule() { @@ -78,10 +76,8 @@ void FSettingsWidgetConstructorEditorModule::RegisterSettingAssets() void FSettingsWidgetConstructorEditorModule::RegisterSettingAssetsCategory() { static const FName CategoryKey = TEXT("SettingsWidgetConstructor"); - static const FText CategoryDisplayName = LOCTEXT("SettingsWidgetConstructorCategory", "Settings Widget Constructor"); + static const FText CategoryDisplayName = NSLOCTEXT("SettingsWidgetConstructorEditorModule", "SettingsWidgetConstructorCategory", "Settings Widget Constructor"); SettingsCategory = IAssetTools::Get().RegisterAdvancedAssetCategory(CategoryKey, CategoryDisplayName); } -#undef LOCTEXT_NAMESPACE - IMPLEMENT_MODULE(FSettingsWidgetConstructorEditorModule, SettingsWidgetConstructorEditor)