Réglages : LPSettingsSubsystem (onglets, bouton titre) et LPColorGradeSubsystem (réglages vidéo couleur)
Phase Réglages (CHG-158..163). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
91259316a6
commit
e46d01d5d8
4 changed files with 1121 additions and 0 deletions
378
Source/LifePlay/LPColorGradeSubsystem.cpp
Normal file
378
Source/LifePlay/LPColorGradeSubsystem.cpp
Normal file
|
|
@ -0,0 +1,378 @@
|
|||
// Voir LPColorGradeSubsystem.h.
|
||||
|
||||
#include "LPColorGradeSubsystem.h"
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Components/HorizontalBox.h"
|
||||
#include "Components/HorizontalBoxSlot.h"
|
||||
#include "Components/PanelWidget.h"
|
||||
#include "Components/ScrollBox.h"
|
||||
#include "Components/ScrollBoxSlot.h"
|
||||
#include "Components/SizeBox.h"
|
||||
#include "Components/Slider.h"
|
||||
#include "Components/TextBlock.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Engine/PostProcessVolume.h"
|
||||
#include "Engine/World.h"
|
||||
#include "LifePlay.h"
|
||||
#include "Misc/ConfigCacheIni.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Styling/CoreStyle.h"
|
||||
#include "Styling/SlateTypes.h"
|
||||
|
||||
namespace LPColorGrade
|
||||
{
|
||||
FString IniPath()
|
||||
{
|
||||
return FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Config/Windows/LPColorGrade.ini"));
|
||||
}
|
||||
|
||||
FString FormatValue(float Value, int32 Decimals)
|
||||
{
|
||||
return FString::Printf(TEXT("%.*f"), Decimals, Value);
|
||||
}
|
||||
|
||||
FSlateFontInfo MenuFont()
|
||||
{
|
||||
FSlateFontInfo Font = FCoreStyle::GetDefaultFontStyle("Regular", 20);
|
||||
Font.OutlineSettings.OutlineSize = 2;
|
||||
Font.OutlineSettings.bApplyOutlineToDropShadows = true;
|
||||
Font.OutlineSettings.OutlineColor = FLinearColor(0.f, 0.f, 0.f, 0.8f);
|
||||
return Font;
|
||||
}
|
||||
|
||||
void FindLook(UWidget* Widget, UTextBlock*& OutText, USlider*& OutSlider)
|
||||
{
|
||||
if (!Widget || (OutText && OutSlider))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!OutText)
|
||||
{
|
||||
OutText = Cast<UTextBlock>(Widget);
|
||||
}
|
||||
if (!OutSlider)
|
||||
{
|
||||
OutSlider = Cast<USlider>(Widget);
|
||||
}
|
||||
if (UUserWidget* User = Cast<UUserWidget>(Widget))
|
||||
{
|
||||
FindLook(User->GetRootWidget(), OutText, OutSlider);
|
||||
}
|
||||
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
|
||||
{
|
||||
for (int32 Index = 0; Index < Panel->GetChildrenCount() && !(OutText && OutSlider); ++Index)
|
||||
{
|
||||
FindLook(Panel->GetChildAt(Index), OutText, OutSlider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
Load();
|
||||
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPColorGradeSubsystem::Tick), 0.5f);
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::Deinitialize()
|
||||
{
|
||||
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
bool ULPColorGradeSubsystem::Tick(float DeltaTime)
|
||||
{
|
||||
(void)DeltaTime;
|
||||
EnsureVolume();
|
||||
EnsureControls();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::Load()
|
||||
{
|
||||
const FString Ini = LPColorGrade::IniPath();
|
||||
FConfigFile File;
|
||||
File.Read(Ini);
|
||||
auto Read = [&File](const TCHAR* Key, float& Out)
|
||||
{
|
||||
FString Text;
|
||||
if (File.GetString(TEXT("LPColorGrade"), Key, Text))
|
||||
{
|
||||
Out = FCString::Atof(*Text);
|
||||
}
|
||||
};
|
||||
Read(TEXT("Brightness"), Brightness);
|
||||
Read(TEXT("Saturation"), Saturation);
|
||||
Read(TEXT("Contrast"), Contrast);
|
||||
Read(TEXT("WhiteBalance"), WhiteBalance);
|
||||
Read(TEXT("Tint"), Tint);
|
||||
Brightness = FMath::Clamp(Brightness, -2.f, 2.f);
|
||||
Saturation = FMath::Clamp(Saturation, 0.f, 2.f);
|
||||
Contrast = FMath::Clamp(Contrast, 0.f, 2.f);
|
||||
WhiteBalance = FMath::Clamp(WhiteBalance, 1500.f, 15000.f);
|
||||
Tint = FMath::Clamp(Tint, -1.f, 1.f);
|
||||
UE_LOG(LogLifePlay, Display, TEXT("Couleur : relu Brightness %.2f, Saturation %.2f, Contrast %.2f, White Balance %.0f, Tint %.2f depuis %s"), Brightness, Saturation, Contrast, WhiteBalance, Tint, *Ini);
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::Save() const
|
||||
{
|
||||
const FString Ini = LPColorGrade::IniPath();
|
||||
FConfigFile File;
|
||||
File.Read(Ini);
|
||||
auto Write = [&File](const TCHAR* Key, float Value)
|
||||
{
|
||||
File.SetString(TEXT("LPColorGrade"), Key, *FString::SanitizeFloat(Value));
|
||||
};
|
||||
Write(TEXT("Brightness"), Brightness);
|
||||
Write(TEXT("Saturation"), Saturation);
|
||||
Write(TEXT("Contrast"), Contrast);
|
||||
Write(TEXT("WhiteBalance"), WhiteBalance);
|
||||
Write(TEXT("Tint"), Tint);
|
||||
File.Write(Ini);
|
||||
UE_LOG(LogLifePlay, Display, TEXT("Couleur : Brightness %.2f, Saturation %.2f, Contrast %.2f, White Balance %.0f, Tint %.2f enregistres dans %s"), Brightness, Saturation, Contrast, WhiteBalance, Tint, *Ini);
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::ApplyGrade()
|
||||
{
|
||||
APostProcessVolume* Volume = GradeVolume.Get();
|
||||
if (!Volume)
|
||||
{
|
||||
return;
|
||||
}
|
||||
FPostProcessSettings& Settings = Volume->Settings;
|
||||
Settings.bOverride_AutoExposureBias = true;
|
||||
Settings.AutoExposureBias = Brightness;
|
||||
Settings.bOverride_ColorSaturation = true;
|
||||
Settings.ColorSaturation = FVector4(Saturation, Saturation, Saturation, 1.f);
|
||||
Settings.bOverride_ColorContrast = true;
|
||||
Settings.ColorContrast = FVector4(Contrast, Contrast, Contrast, 1.f);
|
||||
Settings.bOverride_TemperatureType = true;
|
||||
Settings.TemperatureType = TEMP_WhiteBalance;
|
||||
Settings.bOverride_WhiteTemp = true;
|
||||
Settings.WhiteTemp = WhiteBalance;
|
||||
Settings.bOverride_WhiteTint = true;
|
||||
Settings.WhiteTint = Tint;
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::EnsureVolume()
|
||||
{
|
||||
UWorld* World = GetWorld();
|
||||
if (!World || !World->IsGameWorld())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (GradeVolume.IsValid() && GradeVolume->GetWorld() == World)
|
||||
{
|
||||
ApplyGrade();
|
||||
return;
|
||||
}
|
||||
FActorSpawnParameters Params;
|
||||
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||||
Params.ObjectFlags |= RF_Transient;
|
||||
APostProcessVolume* Volume = World->SpawnActor<APostProcessVolume>(APostProcessVolume::StaticClass(), Params);
|
||||
if (!Volume)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Volume->bUnbound = true;
|
||||
Volume->bEnabled = true;
|
||||
Volume->BlendWeight = 1.f;
|
||||
Volume->Priority = 100.f;
|
||||
GradeVolume = Volume;
|
||||
ApplyGrade();
|
||||
UE_LOG(LogLifePlay, Display, TEXT("Couleur : exposition, saturation, contraste et balance des blancs"));
|
||||
}
|
||||
|
||||
USlider* ULPColorGradeSubsystem::AddRow(UScrollBox* Scroll, const TCHAR* Name, const TCHAR* Label, float Min, float Max, float Step, float Value, FName Handler, const TCHAR* Tip, const FSlateFontInfo& Font, const FSlateColor& Color, const FSliderStyle* SliderStyle)
|
||||
{
|
||||
UHorizontalBox* Row = NewObject<UHorizontalBox>(Scroll, Name);
|
||||
UTextBlock* Caption = NewObject<UTextBlock>(Row);
|
||||
Caption->SetText(FText::FromString(Label));
|
||||
Caption->SetFont(Font);
|
||||
Caption->SetColorAndOpacity(Color);
|
||||
USizeBox* CaptionBox = NewObject<USizeBox>(Row);
|
||||
CaptionBox->SetWidthOverride(220.f);
|
||||
CaptionBox->AddChild(Caption);
|
||||
USlider* Slider = NewObject<USlider>(Row);
|
||||
if (SliderStyle)
|
||||
{
|
||||
Slider->SetWidgetStyle(*SliderStyle);
|
||||
}
|
||||
Slider->SetMinValue(Min);
|
||||
Slider->SetMaxValue(Max);
|
||||
Slider->SetStepSize(Step);
|
||||
Slider->SetValue(Value);
|
||||
UTextBlock* Readout = NewObject<UTextBlock>(Row);
|
||||
Readout->SetFont(Font);
|
||||
Readout->SetColorAndOpacity(Color);
|
||||
if (UHorizontalBoxSlot* Slot = Row->AddChildToHorizontalBox(CaptionBox))
|
||||
{
|
||||
Slot->SetVerticalAlignment(VAlign_Center);
|
||||
Slot->SetPadding(FMargin(10.f, 0.f, 20.f, 0.f));
|
||||
}
|
||||
if (UHorizontalBoxSlot* Slot = Row->AddChildToHorizontalBox(Slider))
|
||||
{
|
||||
Slot->SetSize(FSlateChildSize(ESlateSizeRule::Fill));
|
||||
Slot->SetVerticalAlignment(VAlign_Center);
|
||||
Slot->SetPadding(FMargin(0.f, 0.f, 20.f, 0.f));
|
||||
}
|
||||
if (UHorizontalBoxSlot* Slot = Row->AddChildToHorizontalBox(Readout))
|
||||
{
|
||||
Slot->SetVerticalAlignment(VAlign_Center);
|
||||
Slot->SetPadding(FMargin(0.f, 0.f, 10.f, 0.f));
|
||||
}
|
||||
if (UScrollBoxSlot* Slot = Cast<UScrollBoxSlot>(Scroll->AddChild(Row)))
|
||||
{
|
||||
Slot->SetPadding(FMargin(0.f, 0.f, 0.f, 10.f));
|
||||
}
|
||||
Row->SetToolTipText(FText::FromString(Tip));
|
||||
FScriptDelegate Delegate;
|
||||
Delegate.BindUFunction(this, Handler);
|
||||
Slider->OnValueChanged.Add(Delegate);
|
||||
if (Name == FString(TEXT("LPColorBrightness")))
|
||||
{
|
||||
BrightnessValue = Readout;
|
||||
}
|
||||
else if (Name == FString(TEXT("LPColorSaturation")))
|
||||
{
|
||||
SaturationValue = Readout;
|
||||
}
|
||||
else if (Name == FString(TEXT("LPColorContrast")))
|
||||
{
|
||||
ContrastValue = Readout;
|
||||
}
|
||||
else if (Name == FString(TEXT("LPColorWhiteBalance")))
|
||||
{
|
||||
WhiteBalanceValue = Readout;
|
||||
}
|
||||
else if (Name == FString(TEXT("LPColorTint")))
|
||||
{
|
||||
TintValue = Readout;
|
||||
}
|
||||
return Slider;
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::EnsureControls()
|
||||
{
|
||||
UScrollBox* Scroll = nullptr;
|
||||
for (TObjectIterator<UScrollBox> It; It; ++It)
|
||||
{
|
||||
UScrollBox* Candidate = *It;
|
||||
if (!Candidate || Candidate->GetFName() != TEXT("SettingsScrollBox") || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const UUserWidget* Owner = Candidate->GetTypedOuter<UUserWidget>();
|
||||
if (!Owner || Owner->HasAnyFlags(RF_ClassDefaultObject) || Owner->GetGameInstance() != GetGameInstance())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Scroll = Candidate;
|
||||
break;
|
||||
}
|
||||
if (!Scroll)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||||
{
|
||||
if (UWidget* Child = Scroll->GetChildAt(Index))
|
||||
{
|
||||
if (Child->GetFName() == TEXT("LPColorBrightness"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
UTextBlock* SampleText = nullptr;
|
||||
USlider* SampleSlider = nullptr;
|
||||
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||||
{
|
||||
LPColorGrade::FindLook(Scroll->GetChildAt(Index), SampleText, SampleSlider);
|
||||
}
|
||||
const FSlateFontInfo Font = SampleText ? SampleText->GetFont() : LPColorGrade::MenuFont();
|
||||
const FSlateColor Color = SampleText ? SampleText->GetColorAndOpacity() : FSlateColor(FLinearColor(1.f, 1.f, 1.f, 0.95f));
|
||||
const FSliderStyle* SliderStyle = SampleSlider ? &SampleSlider->GetWidgetStyle() : nullptr;
|
||||
AddRow(Scroll, TEXT("LPColorBrightness"), TEXT("Brightness"), -2.f, 2.f, 0.05f, Brightness, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnBrightnessChanged), TEXT("Exposure compensation. -1 is twice as dark, +1 is twice as bright."), Font, Color, SliderStyle);
|
||||
AddRow(Scroll, TEXT("LPColorSaturation"), TEXT("Saturation"), 0.f, 2.f, 0.05f, Saturation, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnSaturationChanged), TEXT("Color intensity. 1 is unchanged, 0 is gray."), Font, Color, SliderStyle);
|
||||
AddRow(Scroll, TEXT("LPColorContrast"), TEXT("Contrast"), 0.f, 2.f, 0.05f, Contrast, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnContrastChanged), TEXT("Range between light and dark. 1 is unchanged."), Font, Color, SliderStyle);
|
||||
AddRow(Scroll, TEXT("LPColorWhiteBalance"), TEXT("White Balance"), 1500.f, 15000.f, 50.f, WhiteBalance, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnWhiteBalanceChanged), TEXT("Color temperature in kelvin. 6500 is daylight."), Font, Color, SliderStyle);
|
||||
AddRow(Scroll, TEXT("LPColorTint"), TEXT("Tint"), -1.f, 1.f, 0.01f, Tint, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnTintChanged), TEXT("Magenta to green. 0 is unchanged."), Font, Color, SliderStyle);
|
||||
if (UTextBlock* Readout = BrightnessValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Brightness, 2)));
|
||||
}
|
||||
if (UTextBlock* Readout = SaturationValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Saturation, 2)));
|
||||
}
|
||||
if (UTextBlock* Readout = ContrastValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Contrast, 2)));
|
||||
}
|
||||
if (UTextBlock* Readout = WhiteBalanceValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(WhiteBalance, 0)));
|
||||
}
|
||||
if (UTextBlock* Readout = TintValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Tint, 2)));
|
||||
}
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::OnBrightnessChanged(float Value)
|
||||
{
|
||||
Brightness = Value;
|
||||
if (UTextBlock* Readout = BrightnessValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||||
}
|
||||
ApplyGrade();
|
||||
Save();
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::OnSaturationChanged(float Value)
|
||||
{
|
||||
Saturation = Value;
|
||||
if (UTextBlock* Readout = SaturationValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||||
}
|
||||
ApplyGrade();
|
||||
Save();
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::OnContrastChanged(float Value)
|
||||
{
|
||||
Contrast = Value;
|
||||
if (UTextBlock* Readout = ContrastValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||||
}
|
||||
ApplyGrade();
|
||||
Save();
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::OnWhiteBalanceChanged(float Value)
|
||||
{
|
||||
WhiteBalance = Value;
|
||||
if (UTextBlock* Readout = WhiteBalanceValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 0)));
|
||||
}
|
||||
ApplyGrade();
|
||||
Save();
|
||||
}
|
||||
|
||||
void ULPColorGradeSubsystem::OnTintChanged(float Value)
|
||||
{
|
||||
Tint = Value;
|
||||
if (UTextBlock* Readout = TintValue.Get())
|
||||
{
|
||||
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||||
}
|
||||
ApplyGrade();
|
||||
Save();
|
||||
}
|
||||
64
Source/LifePlay/LPColorGradeSubsystem.h
Normal file
64
Source/LifePlay/LPColorGradeSubsystem.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Luminosite, saturation, contraste et balance des blancs.
|
||||
//
|
||||
// Ce sont les reglages globaux du panneau Color Grading d'Unreal (FPostProcessSettings) :
|
||||
// la compensation d'exposition, ColorSaturation, ColorContrast, et la balance des blancs
|
||||
// (WhiteTemp / WhiteTint, methode White Balance). Ils s'appliquent a toute la vue par un
|
||||
// volume de post-traitement non borne. Les valeurs neutres du moteur ne changent pas l'image.
|
||||
// Enregistre dans Saved/Config/Windows/LPColorGrade.ini, pas dans GameSettings.sav.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Containers/Ticker.h"
|
||||
#include "Styling/SlateTypes.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "LPColorGradeSubsystem.generated.h"
|
||||
|
||||
class APostProcessVolume;
|
||||
class UScrollBox;
|
||||
class USlider;
|
||||
class UTextBlock;
|
||||
|
||||
UCLASS()
|
||||
class LIFEPLAY_API ULPColorGradeSubsystem : public UGameInstanceSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
UFUNCTION()
|
||||
void OnBrightnessChanged(float Value);
|
||||
UFUNCTION()
|
||||
void OnSaturationChanged(float Value);
|
||||
UFUNCTION()
|
||||
void OnContrastChanged(float Value);
|
||||
UFUNCTION()
|
||||
void OnWhiteBalanceChanged(float Value);
|
||||
UFUNCTION()
|
||||
void OnTintChanged(float Value);
|
||||
|
||||
private:
|
||||
bool Tick(float DeltaTime);
|
||||
void EnsureControls();
|
||||
void EnsureVolume();
|
||||
void ApplyGrade();
|
||||
void Load();
|
||||
void Save() const;
|
||||
USlider* AddRow(UScrollBox* Scroll, const TCHAR* Name, const TCHAR* Label, float Min, float Max, float Step, float Value, FName Handler, const TCHAR* Tip, const FSlateFontInfo& Font, const FSlateColor& Color, const FSliderStyle* SliderStyle);
|
||||
|
||||
FTSTicker::FDelegateHandle TickHandle;
|
||||
TWeakObjectPtr<APostProcessVolume> GradeVolume;
|
||||
TWeakObjectPtr<UTextBlock> BrightnessValue;
|
||||
TWeakObjectPtr<UTextBlock> SaturationValue;
|
||||
TWeakObjectPtr<UTextBlock> ContrastValue;
|
||||
TWeakObjectPtr<UTextBlock> WhiteBalanceValue;
|
||||
TWeakObjectPtr<UTextBlock> TintValue;
|
||||
|
||||
float Brightness = 0.f;
|
||||
float Saturation = 1.f;
|
||||
float Contrast = 1.f;
|
||||
float WhiteBalance = 6500.f;
|
||||
float Tint = 0.f;
|
||||
};
|
||||
612
Source/LifePlay/LPSettingsSubsystem.cpp
Normal file
612
Source/LifePlay/LPSettingsSubsystem.cpp
Normal file
|
|
@ -0,0 +1,612 @@
|
|||
// Reglages par onglets. Voir LPSettingsSubsystem.h.
|
||||
|
||||
#include "LPSettingsSubsystem.h"
|
||||
|
||||
#include "Blueprint/UserWidget.h"
|
||||
#include "Components/Button.h"
|
||||
#include "Components/ButtonSlot.h"
|
||||
#include "Components/CanvasPanel.h"
|
||||
#include "Components/CanvasPanelSlot.h"
|
||||
#include "Components/HorizontalBox.h"
|
||||
#include "Components/HorizontalBoxSlot.h"
|
||||
#include "Components/Image.h"
|
||||
#include "Components/NativeWidgetHost.h"
|
||||
#include "Components/Overlay.h"
|
||||
#include "Components/OverlaySlot.h"
|
||||
#include "Components/ScrollBox.h"
|
||||
#include "Components/SizeBox.h"
|
||||
#include "Components/TextBlock.h"
|
||||
#include "Components/PanelWidget.h"
|
||||
#include "Components/VerticalBox.h"
|
||||
#include "Components/VerticalBoxSlot.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Engine/Texture2D.h"
|
||||
#include "LPKeyboardSubsystem.h"
|
||||
#include "LifePlay.h"
|
||||
#include "Styling/CoreStyle.h"
|
||||
#include "UObject/TextProperty.h"
|
||||
|
||||
namespace LPSettingsUi
|
||||
{
|
||||
const TCHAR* TabNames[] = {
|
||||
TEXT("General"), TEXT("Audio"), TEXT("Video"), TEXT("Keyboard"), TEXT("Lewd"), TEXT("Misc")
|
||||
};
|
||||
constexpr int32 TabGeneral = 0;
|
||||
constexpr int32 TabAudio = 1;
|
||||
constexpr int32 TabVideo = 2;
|
||||
constexpr int32 TabKeyboard = 3;
|
||||
constexpr int32 TabLewd = 4;
|
||||
constexpr int32 TabMisc = 5;
|
||||
|
||||
FString VolumeLabel(const FString& Text)
|
||||
{
|
||||
if (Text.Equals(TEXT("Volume - Sex Moans"), ESearchCase::IgnoreCase) || Text.Equals(TEXT("Volume - Sex Moan"), ESearchCase::IgnoreCase))
|
||||
{
|
||||
return TEXT("Volume - SFX");
|
||||
}
|
||||
if (Text.Equals(TEXT("Volume - Sex"), ESearchCase::IgnoreCase))
|
||||
{
|
||||
return TEXT("Volume - Dialogue");
|
||||
}
|
||||
return Text;
|
||||
}
|
||||
|
||||
void RenameVolumes(UWidget* Widget)
|
||||
{
|
||||
if (!Widget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (FTextProperty* Setting = CastField<FTextProperty>(Widget->GetClass()->FindPropertyByName(TEXT("SettingText"))))
|
||||
{
|
||||
const FString Next = VolumeLabel(Setting->GetPropertyValue_InContainer(Widget).ToString());
|
||||
if (Next != Setting->GetPropertyValue_InContainer(Widget).ToString())
|
||||
{
|
||||
Setting->SetPropertyValue_InContainer(Widget, FText::FromString(Next));
|
||||
}
|
||||
}
|
||||
if (UTextBlock* Block = Cast<UTextBlock>(Widget))
|
||||
{
|
||||
const FString Next = VolumeLabel(Block->GetText().ToString());
|
||||
if (Next != Block->GetText().ToString())
|
||||
{
|
||||
Block->SetText(FText::FromString(Next));
|
||||
}
|
||||
}
|
||||
if (UUserWidget* User = Cast<UUserWidget>(Widget))
|
||||
{
|
||||
RenameVolumes(User->GetRootWidget());
|
||||
}
|
||||
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
|
||||
{
|
||||
for (int32 Index = 0; Index < Panel->GetChildrenCount(); ++Index)
|
||||
{
|
||||
RenameVolumes(Panel->GetChildAt(Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsOpen(const UWidget* Widget)
|
||||
{
|
||||
if (!Widget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const ESlateVisibility Visibility = Widget->GetVisibility();
|
||||
return Visibility != ESlateVisibility::Collapsed && Visibility != ESlateVisibility::Hidden;
|
||||
}
|
||||
|
||||
FString RowText(const UWidget* Widget)
|
||||
{
|
||||
FString Text;
|
||||
if (!Widget)
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
if (const FTextProperty* Setting = CastField<FTextProperty>(Widget->GetClass()->FindPropertyByName(TEXT("SettingText"))))
|
||||
{
|
||||
Text += Setting->GetPropertyValue_InContainer(Widget).ToString();
|
||||
}
|
||||
Text += TEXT(" ") + Widget->GetToolTipText().ToString();
|
||||
TArray<UWidget*> Pending;
|
||||
Pending.Add(const_cast<UWidget*>(Widget));
|
||||
while (Pending.Num() > 0)
|
||||
{
|
||||
UWidget* Current = Pending.Pop(EAllowShrinking::No);
|
||||
if (const UTextBlock* Block = Cast<UTextBlock>(Current))
|
||||
{
|
||||
Text += TEXT(" ") + Block->GetText().ToString();
|
||||
}
|
||||
if (const UUserWidget* User = Cast<UUserWidget>(Current))
|
||||
{
|
||||
if (UWidget* Root = User->GetRootWidget())
|
||||
{
|
||||
Pending.Add(Root);
|
||||
}
|
||||
}
|
||||
if (const UPanelWidget* Panel = Cast<UPanelWidget>(Current))
|
||||
{
|
||||
for (int32 Index = 0; Index < Panel->GetChildrenCount(); ++Index)
|
||||
{
|
||||
Pending.Add(Panel->GetChildAt(Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Text;
|
||||
}
|
||||
|
||||
int32 CategoryOf(const UWidget* Widget)
|
||||
{
|
||||
if (Widget && Widget->GetFName() == TEXT("BackButton"))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (Widget && Widget->GetName().StartsWith(TEXT("LPColor")))
|
||||
{
|
||||
return TabVideo;
|
||||
}
|
||||
const FString Text = RowText(Widget).ToLower();
|
||||
if (Text.Contains(TEXT("volume")) || Text.Contains(TEXT("audio")) || Text.Contains(TEXT("sound")) || Text.Contains(TEXT("music")))
|
||||
{
|
||||
return TabAudio;
|
||||
}
|
||||
if (Text.Contains(TEXT("fps")) || Text.Contains(TEXT("screen")) || Text.Contains(TEXT("shadow")) || Text.Contains(TEXT("quality"))
|
||||
|| Text.Contains(TEXT("fullscreen")) || Text.Contains(TEXT("window")) || Text.Contains(TEXT("toon")) || Text.Contains(TEXT("depth of field"))
|
||||
|| Text.Contains(TEXT("censor")) || Text.Contains(TEXT("morph")) || Text.Contains(TEXT("dog")) || Text.Contains(TEXT("jiggle"))
|
||||
|| Text.Contains(TEXT("resolution")) || Text.Contains(TEXT("vsync")) || Text.Contains(TEXT("brightness")))
|
||||
{
|
||||
return TabVideo;
|
||||
}
|
||||
if (Text.Contains(TEXT("sex")) || Text.Contains(TEXT("condom")) || Text.Contains(TEXT("squirt")) || Text.Contains(TEXT("pregnan"))
|
||||
|| Text.Contains(TEXT("underwear")) || Text.Contains(TEXT("orientation")) || Text.Contains(TEXT("trans")) || Text.Contains(TEXT("relationship"))
|
||||
|| Text.Contains(TEXT("moan")) || Text.Contains(TEXT("lewd")))
|
||||
{
|
||||
return TabLewd;
|
||||
}
|
||||
if (Text.Contains(TEXT("difficult")) || Text.Contains(TEXT("clock")) || Text.Contains(TEXT("camera")) || Text.Contains(TEXT("scene"))
|
||||
|| Text.Contains(TEXT("pause")) || Text.Contains(TEXT("timeout")) || Text.Contains(TEXT("tutorial")) || Text.Contains(TEXT("marker"))
|
||||
|| Text.Contains(TEXT("building")) || Text.Contains(TEXT("animation")) || Text.Contains(TEXT("action filter")) || Text.Contains(TEXT("dye"))
|
||||
|| Text.Contains(TEXT("stat")) || Text.Contains(TEXT("child")) || Text.Contains(TEXT("redress")))
|
||||
{
|
||||
return TabGeneral;
|
||||
}
|
||||
return TabMisc;
|
||||
}
|
||||
|
||||
UTextBlock* FirstText(UWidget* Widget)
|
||||
{
|
||||
if (!Widget)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
if (UTextBlock* Text = Cast<UTextBlock>(Widget))
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
if (UUserWidget* User = Cast<UUserWidget>(Widget))
|
||||
{
|
||||
if (UTextBlock* Text = FirstText(User->GetRootWidget()))
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
}
|
||||
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
|
||||
{
|
||||
for (int32 Index = 0; Index < Panel->GetChildrenCount(); ++Index)
|
||||
{
|
||||
if (UTextBlock* Text = FirstText(Panel->GetChildAt(Index)))
|
||||
{
|
||||
return Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UImage* RoundIcon(UWidget* Owner, const TCHAR* TexturePath, float Size)
|
||||
{
|
||||
UImage* Image = NewObject<UImage>(Owner);
|
||||
if (UTexture2D* Texture = LoadObject<UTexture2D>(nullptr, TexturePath))
|
||||
{
|
||||
FSlateBrush Brush;
|
||||
Brush.SetResourceObject(Texture);
|
||||
Brush.ImageSize = FVector2D(Size, Size);
|
||||
Image->SetBrush(Brush);
|
||||
}
|
||||
return Image;
|
||||
}
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||||
{
|
||||
Super::Initialize(Collection);
|
||||
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPSettingsSubsystem::Tick), 0.5f);
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::Deinitialize()
|
||||
{
|
||||
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
|
||||
Super::Deinitialize();
|
||||
}
|
||||
|
||||
bool ULPSettingsSubsystem::Tick(float DeltaTime)
|
||||
{
|
||||
(void)DeltaTime;
|
||||
PlaceSettingsButton();
|
||||
UScrollBox* Scroll = nullptr;
|
||||
for (TObjectIterator<UScrollBox> It; It; ++It)
|
||||
{
|
||||
UScrollBox* Candidate = *It;
|
||||
if (!Candidate || Candidate->GetFName() != TEXT("SettingsScrollBox") || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const UUserWidget* MenuOwner = Candidate->GetTypedOuter<UUserWidget>();
|
||||
if (!MenuOwner || MenuOwner->HasAnyFlags(RF_ClassDefaultObject) || MenuOwner->GetGameInstance() != GetGameInstance())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Scroll = Candidate;
|
||||
break;
|
||||
}
|
||||
if (!Scroll)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
SettingsList = Scroll;
|
||||
const bool bOpen = LPSettingsUi::IsOpen(Scroll);
|
||||
if (TabBar.IsValid())
|
||||
{
|
||||
TabBar->SetVisibility(bOpen ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
|
||||
}
|
||||
if (KeyboardHost.IsValid() && !bOpen)
|
||||
{
|
||||
KeyboardHost->SetVisibility(ESlateVisibility::Collapsed);
|
||||
bKeyboardPage = false;
|
||||
}
|
||||
if (!bOpen)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
EnsureTabs(Scroll);
|
||||
if (Scroll->GetChildrenCount() != LastChildCount)
|
||||
{
|
||||
LastChildCount = Scroll->GetChildrenCount();
|
||||
ApplyRows();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::OpenSettings()
|
||||
{
|
||||
if (UButton* Source = SourceSettings.Get())
|
||||
{
|
||||
Source->OnClicked.Broadcast();
|
||||
}
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::PlaceSettingsButton()
|
||||
{
|
||||
UVerticalBox* Menu = nullptr;
|
||||
UButton* TitleMods = nullptr;
|
||||
UButton* Original = nullptr;
|
||||
UButton* Ours = nullptr;
|
||||
for (TObjectIterator<UVerticalBox> It; It; ++It)
|
||||
{
|
||||
UVerticalBox* Box = *It;
|
||||
if (!Box || Box->GetFName() != TEXT("MainMenuOptions") || Box->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const UUserWidget* MenuOwner = Box->GetTypedOuter<UUserWidget>();
|
||||
if (!MenuOwner || MenuOwner->HasAnyFlags(RF_ClassDefaultObject) || MenuOwner->GetGameInstance() != GetGameInstance())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
UButton* FoundTitle = nullptr;
|
||||
for (int32 Index = 0; Index < Box->GetChildrenCount(); ++Index)
|
||||
{
|
||||
if (UButton* Child = Cast<UButton>(Box->GetChildAt(Index)))
|
||||
{
|
||||
if (Child->GetFName() == TEXT("ModManagerTitleButton"))
|
||||
{
|
||||
FoundTitle = Child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (FoundTitle)
|
||||
{
|
||||
Menu = Box;
|
||||
TitleMods = FoundTitle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!Menu || !TitleMods)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int32 Index = 0; Index < Menu->GetChildrenCount(); ++Index)
|
||||
{
|
||||
UButton* Child = Cast<UButton>(Menu->GetChildAt(Index));
|
||||
if (!Child)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (Child->GetFName() == TEXT("SettingsButton"))
|
||||
{
|
||||
Original = Child;
|
||||
}
|
||||
else if (Child->GetFName() == TEXT("LPSettingsTitleButton"))
|
||||
{
|
||||
Ours = Child;
|
||||
}
|
||||
}
|
||||
if (Original)
|
||||
{
|
||||
SourceSettings = Original;
|
||||
}
|
||||
if (!Ours)
|
||||
{
|
||||
Ours = NewObject<UButton>(Menu, TEXT("LPSettingsTitleButton"));
|
||||
Ours->SetStyle(TitleMods->GetStyle());
|
||||
UOverlay* Icon = NewObject<UOverlay>(Ours);
|
||||
UImage* Circle = LPSettingsUi::RoundIcon(Icon, TEXT("/Game/Heavy/New/whitecircle.whitecircle"), 50.f);
|
||||
UImage* Gear = LPSettingsUi::RoundIcon(Icon, TEXT("/Game/Heavy/New/settings.settings"), 42.f);
|
||||
if (UOverlaySlot* Slot = Cast<UOverlaySlot>(Icon->AddChild(Circle)))
|
||||
{
|
||||
Slot->SetHorizontalAlignment(HAlign_Fill);
|
||||
Slot->SetVerticalAlignment(VAlign_Fill);
|
||||
}
|
||||
if (UOverlaySlot* Slot = Cast<UOverlaySlot>(Icon->AddChild(Gear)))
|
||||
{
|
||||
Slot->SetHorizontalAlignment(HAlign_Fill);
|
||||
Slot->SetVerticalAlignment(VAlign_Fill);
|
||||
Slot->SetPadding(FMargin(6.f));
|
||||
}
|
||||
USizeBox* IconFrame = NewObject<USizeBox>(Ours);
|
||||
IconFrame->SetWidthOverride(50.f);
|
||||
IconFrame->SetHeightOverride(50.f);
|
||||
IconFrame->AddChild(Icon);
|
||||
UTextBlock* Label = NewObject<UTextBlock>(Ours);
|
||||
Label->SetText(FText::FromString(TEXT("Settings")));
|
||||
if (const UTextBlock* Sample = LPSettingsUi::FirstText(TitleMods))
|
||||
{
|
||||
Label->SetFont(Sample->GetFont());
|
||||
Label->SetColorAndOpacity(Sample->GetColorAndOpacity());
|
||||
Label->SetShadowOffset(Sample->GetShadowOffset());
|
||||
}
|
||||
else
|
||||
{
|
||||
Label->SetFont(FCoreStyle::GetDefaultFontStyle("Regular", 26));
|
||||
}
|
||||
UHorizontalBox* Row = NewObject<UHorizontalBox>(Ours);
|
||||
if (UHorizontalBoxSlot* Slot = Row->AddChildToHorizontalBox(IconFrame))
|
||||
{
|
||||
Slot->SetPadding(FMargin(0.f, 0.f, 10.f, 0.f));
|
||||
Slot->SetVerticalAlignment(VAlign_Center);
|
||||
}
|
||||
if (UHorizontalBoxSlot* Slot = Row->AddChildToHorizontalBox(Label))
|
||||
{
|
||||
Slot->SetVerticalAlignment(VAlign_Center);
|
||||
}
|
||||
Ours->SetContent(Row);
|
||||
if (UButtonSlot* ContentSlot = Cast<UButtonSlot>(Row->Slot))
|
||||
{
|
||||
ContentSlot->SetHorizontalAlignment(HAlign_Left);
|
||||
ContentSlot->SetVerticalAlignment(VAlign_Center);
|
||||
}
|
||||
if (Original)
|
||||
{
|
||||
Ours->SetToolTipText(Original->GetToolTipText());
|
||||
}
|
||||
FScriptDelegate Delegate;
|
||||
Delegate.BindUFunction(this, GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, OpenSettings));
|
||||
Ours->OnClicked.Add(Delegate);
|
||||
UE_LOG(LogLifePlay, Display, TEXT("Reglages : entree Settings ajoutee sur l'ecran titre"));
|
||||
}
|
||||
// InsertChildAt ne réordonne que le tableau UMG. La boîte Slate, elle, garde le bouton en dernier,
|
||||
// donc sous Exit. On reconstruit les emplacements pour que l'ordre peint soit celui du tableau.
|
||||
if (OrderedMenu.Get() != Menu)
|
||||
{
|
||||
struct FKept
|
||||
{
|
||||
UWidget* Widget = nullptr;
|
||||
FMargin Padding;
|
||||
EHorizontalAlignment HAlign = HAlign_Fill;
|
||||
EVerticalAlignment VAlign = VAlign_Fill;
|
||||
FSlateChildSize Size;
|
||||
};
|
||||
TArray<FKept> Kept;
|
||||
for (int32 Index = 0; Index < Menu->GetChildrenCount(); ++Index)
|
||||
{
|
||||
UWidget* Child = Menu->GetChildAt(Index);
|
||||
if (!Child || Child == Ours)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
FKept Item;
|
||||
Item.Widget = Child;
|
||||
if (const UVerticalBoxSlot* Slot = Cast<UVerticalBoxSlot>(Child->Slot))
|
||||
{
|
||||
Item.Padding = Slot->GetPadding();
|
||||
Item.HAlign = Slot->GetHorizontalAlignment();
|
||||
Item.VAlign = Slot->GetVerticalAlignment();
|
||||
Item.Size = Slot->GetSize();
|
||||
}
|
||||
Kept.Add(Item);
|
||||
}
|
||||
FKept SettingsItem;
|
||||
SettingsItem.Widget = Ours;
|
||||
SettingsItem.Padding = FMargin(0.f, 0.f, 0.f, 10.f);
|
||||
SettingsItem.HAlign = HAlign_Fill;
|
||||
if (const UVerticalBoxSlot* TitleSlot = Cast<UVerticalBoxSlot>(TitleMods->Slot))
|
||||
{
|
||||
SettingsItem.Padding = TitleSlot->GetPadding();
|
||||
SettingsItem.HAlign = TitleSlot->GetHorizontalAlignment();
|
||||
SettingsItem.VAlign = TitleSlot->GetVerticalAlignment();
|
||||
SettingsItem.Size = TitleSlot->GetSize();
|
||||
}
|
||||
int32 InsertAt = Kept.Num();
|
||||
for (int32 Index = 0; Index < Kept.Num(); ++Index)
|
||||
{
|
||||
if (Kept[Index].Widget == TitleMods)
|
||||
{
|
||||
InsertAt = Index + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Kept.Insert(SettingsItem, InsertAt);
|
||||
Menu->ClearChildren();
|
||||
for (const FKept& Item : Kept)
|
||||
{
|
||||
if (UVerticalBoxSlot* Slot = Cast<UVerticalBoxSlot>(Menu->AddChild(Item.Widget)))
|
||||
{
|
||||
Slot->SetPadding(Item.Padding);
|
||||
Slot->SetHorizontalAlignment(Item.HAlign);
|
||||
Slot->SetVerticalAlignment(Item.VAlign);
|
||||
Slot->SetSize(Item.Size);
|
||||
}
|
||||
}
|
||||
OrderedMenu = Menu;
|
||||
UE_LOG(LogLifePlay, Display, TEXT("Reglages : Settings place apres Mod Manager"));
|
||||
}
|
||||
const ESlateVisibility TitleVisibility = TitleMods->GetVisibility();
|
||||
if (Ours->GetVisibility() != TitleVisibility)
|
||||
{
|
||||
Ours->SetVisibility(TitleVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::EnsureTabs(UScrollBox* Scroll)
|
||||
{
|
||||
if (TabBar.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
UCanvasPanel* Canvas = Cast<UCanvasPanel>(Scroll->GetParent());
|
||||
UCanvasPanelSlot* ScrollSlot = Cast<UCanvasPanelSlot>(Scroll->Slot);
|
||||
if (!Canvas || !ScrollSlot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
UHorizontalBox* Bar = NewObject<UHorizontalBox>(Canvas, TEXT("LPSettingsTabs"));
|
||||
UCanvasPanelSlot* BarSlot = Canvas->AddChildToCanvas(Bar);
|
||||
if (!BarSlot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
BarSlot->SetAnchors(ScrollSlot->GetAnchors());
|
||||
BarSlot->SetAlignment(ScrollSlot->GetAlignment());
|
||||
BarSlot->SetPosition(ScrollSlot->GetPosition() - FVector2D(0.f, 46.f));
|
||||
BarSlot->SetSize(FVector2D(ScrollSlot->GetSize().X, 40.f));
|
||||
BarSlot->SetZOrder(ScrollSlot->GetZOrder() + 1);
|
||||
TabBar = Bar;
|
||||
TabLabels.Reset();
|
||||
|
||||
const FName Clicks[] = {
|
||||
GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, ShowGeneral),
|
||||
GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, ShowAudio),
|
||||
GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, ShowVideo),
|
||||
GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, ShowKeyboard),
|
||||
GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, ShowLewd),
|
||||
GET_FUNCTION_NAME_CHECKED(ULPSettingsSubsystem, ShowMisc)
|
||||
};
|
||||
for (int32 Index = 0; Index < UE_ARRAY_COUNT(LPSettingsUi::TabNames); ++Index)
|
||||
{
|
||||
UButton* Button = NewObject<UButton>(Bar);
|
||||
UTextBlock* Label = NewObject<UTextBlock>(Button);
|
||||
Label->SetText(FText::FromString(LPSettingsUi::TabNames[Index]));
|
||||
Label->SetFont(FCoreStyle::GetDefaultFontStyle("Bold", 14));
|
||||
Button->SetContent(Label);
|
||||
FButtonStyle Style = Button->GetStyle();
|
||||
Style.NormalPadding = FMargin(10.f, 4.f);
|
||||
Style.PressedPadding = FMargin(10.f, 5.f, 10.f, 3.f);
|
||||
Button->SetStyle(Style);
|
||||
if (UHorizontalBoxSlot* Slot = Cast<UHorizontalBoxSlot>(Bar->AddChild(Button)))
|
||||
{
|
||||
Slot->SetPadding(FMargin(3.f, 0.f));
|
||||
Slot->SetSize(FSlateChildSize(ESlateSizeRule::Automatic));
|
||||
Slot->SetVerticalAlignment(VAlign_Center);
|
||||
}
|
||||
FScriptDelegate Delegate;
|
||||
Delegate.BindUFunction(this, Clicks[Index]);
|
||||
Button->OnClicked.Add(Delegate);
|
||||
TabLabels.Add(Label);
|
||||
}
|
||||
|
||||
UNativeWidgetHost* Host = NewObject<UNativeWidgetHost>(Canvas, TEXT("LPSettingsKeyboard"));
|
||||
if (UCanvasPanelSlot* HostSlot = Canvas->AddChildToCanvas(Host))
|
||||
{
|
||||
HostSlot->SetAnchors(ScrollSlot->GetAnchors());
|
||||
HostSlot->SetAlignment(ScrollSlot->GetAlignment());
|
||||
HostSlot->SetPosition(ScrollSlot->GetPosition() + FVector2D(0.f, 48.f));
|
||||
const FVector2D Size = ScrollSlot->GetSize();
|
||||
HostSlot->SetSize(FVector2D(Size.X, FMath::Max(120.f, Size.Y - 48.f)));
|
||||
HostSlot->SetZOrder(ScrollSlot->GetZOrder() + 1);
|
||||
}
|
||||
Host->SetVisibility(ESlateVisibility::Collapsed);
|
||||
KeyboardHost = Host;
|
||||
ActiveTab = 0;
|
||||
ApplyRows();
|
||||
UE_LOG(LogLifePlay, Display, TEXT("Reglages : onglets General, Audio, Video, Keyboard, Lewd, Misc"));
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::SelectTab(int32 Index)
|
||||
{
|
||||
ActiveTab = Index;
|
||||
ApplyRows();
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::ApplyRows()
|
||||
{
|
||||
UScrollBox* Scroll = SettingsList.Get();
|
||||
if (!Scroll)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int32 Index = 0; Index < TabLabels.Num(); ++Index)
|
||||
{
|
||||
if (UTextBlock* Label = TabLabels[Index].Get())
|
||||
{
|
||||
const bool bOn = Index == ActiveTab;
|
||||
Label->SetColorAndOpacity(FSlateColor(bOn ? FLinearColor(1.f, 0.92f, 0.45f) : FLinearColor(0.75f, 0.75f, 0.75f)));
|
||||
}
|
||||
}
|
||||
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||||
{
|
||||
UWidget* Child = Scroll->GetChildAt(Index);
|
||||
if (!Child || Child->GetFName() == TEXT("LPKeyboardRow"))
|
||||
{
|
||||
if (Child)
|
||||
{
|
||||
Child->SetVisibility(ESlateVisibility::Collapsed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
LPSettingsUi::RenameVolumes(Child);
|
||||
const int32 Category = LPSettingsUi::CategoryOf(Child);
|
||||
const bool bShow = Category < 0 || (ActiveTab != LPSettingsUi::TabKeyboard && Category == ActiveTab);
|
||||
Child->SetVisibility(bShow ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
|
||||
}
|
||||
const bool bKeyboard = ActiveTab == LPSettingsUi::TabKeyboard;
|
||||
if (UNativeWidgetHost* Host = KeyboardHost.Get())
|
||||
{
|
||||
Host->SetVisibility(bKeyboard ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
|
||||
if (bKeyboard && !bKeyboardPage)
|
||||
{
|
||||
if (ULPKeyboardSubsystem* Keys = GetGameInstance()->GetSubsystem<ULPKeyboardSubsystem>())
|
||||
{
|
||||
Host->SetContent(Keys->TakeEmbeddedPage());
|
||||
bKeyboardPage = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ULPSettingsSubsystem::ShowGeneral() { SelectTab(LPSettingsUi::TabGeneral); }
|
||||
void ULPSettingsSubsystem::ShowAudio() { SelectTab(LPSettingsUi::TabAudio); }
|
||||
void ULPSettingsSubsystem::ShowVideo() { SelectTab(LPSettingsUi::TabVideo); }
|
||||
void ULPSettingsSubsystem::ShowKeyboard() { SelectTab(LPSettingsUi::TabKeyboard); }
|
||||
void ULPSettingsSubsystem::ShowLewd() { SelectTab(LPSettingsUi::TabLewd); }
|
||||
void ULPSettingsSubsystem::ShowMisc() { SelectTab(LPSettingsUi::TabMisc); }
|
||||
67
Source/LifePlay/LPSettingsSubsystem.h
Normal file
67
Source/LifePlay/LPSettingsSubsystem.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Reglages par onglets, et entree Settings de l'ecran titre (entre Mod Manager et Donate).
|
||||
//
|
||||
// Les lignes existent deja dans MainMenu.SettingsScrollBox (cases et curseurs du Blueprint).
|
||||
// Ce sous-systeme ne les recree pas : il les montre ou les cache selon l'onglet.
|
||||
// General, Audio, Video, Keyboard (la liste des touches), Lewd, puis Misc.
|
||||
// Aucun Blueprint n'est modifie.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Containers/Ticker.h"
|
||||
#include "Subsystems/GameInstanceSubsystem.h"
|
||||
#include "LPSettingsSubsystem.generated.h"
|
||||
|
||||
class UButton;
|
||||
class UCanvasPanel;
|
||||
class UHorizontalBox;
|
||||
class UNativeWidgetHost;
|
||||
class UScrollBox;
|
||||
class UTextBlock;
|
||||
class UVerticalBox;
|
||||
class UWidget;
|
||||
|
||||
UCLASS()
|
||||
class LIFEPLAY_API ULPSettingsSubsystem : public UGameInstanceSubsystem
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
|
||||
virtual void Deinitialize() override;
|
||||
|
||||
UFUNCTION()
|
||||
void ShowAudio();
|
||||
UFUNCTION()
|
||||
void ShowVideo();
|
||||
UFUNCTION()
|
||||
void ShowLewd();
|
||||
UFUNCTION()
|
||||
void ShowGeneral();
|
||||
UFUNCTION()
|
||||
void ShowKeyboard();
|
||||
UFUNCTION()
|
||||
void ShowMisc();
|
||||
|
||||
UFUNCTION()
|
||||
void OpenSettings();
|
||||
|
||||
private:
|
||||
bool Tick(float DeltaTime);
|
||||
void PlaceSettingsButton();
|
||||
void EnsureTabs(UScrollBox* Scroll);
|
||||
void SelectTab(int32 Index);
|
||||
void ApplyRows();
|
||||
|
||||
FTSTicker::FDelegateHandle TickHandle;
|
||||
int32 ActiveTab = 0;
|
||||
int32 LastChildCount = -1;
|
||||
bool bKeyboardPage = false;
|
||||
|
||||
TWeakObjectPtr<UButton> SourceSettings;
|
||||
TWeakObjectPtr<UVerticalBox> OrderedMenu;
|
||||
TWeakObjectPtr<UScrollBox> SettingsList;
|
||||
TWeakObjectPtr<UHorizontalBox> TabBar;
|
||||
TWeakObjectPtr<UNativeWidgetHost> KeyboardHost;
|
||||
TArray<TWeakObjectPtr<UTextBlock>> TabLabels;
|
||||
};
|
||||
Loading…
Reference in a new issue