2026-10-07 13:49:11 +00:00
|
|
|
// 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"
|
2026-10-07 23:40:47 +00:00
|
|
|
#include "Components/CheckBox.h"
|
2026-10-07 13:49:11 +00:00
|
|
|
#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"
|
2026-10-07 23:40:47 +00:00
|
|
|
#include "Components/SpinBox.h"
|
2026-10-07 13:49:11 +00:00
|
|
|
#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"
|
2026-10-07 23:40:47 +00:00
|
|
|
#include "Styling/SlateTypes.h"
|
2026-10-07 13:49:11 +00:00
|
|
|
#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;
|
2026-10-07 23:40:47 +00:00
|
|
|
constexpr int32 TabAlways = -1;
|
|
|
|
|
constexpr int32 TabHidden = -2;
|
2026-10-07 13:49:11 +00:00
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-07 23:40:47 +00:00
|
|
|
// Libelle visible seulement : les infobulles provoquent des faux positifs
|
|
|
|
|
// (ex. "on screen" → Video, "prefer quality" → Video pour NewAnimationsOnly).
|
2026-10-07 13:49:11 +00:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
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"))
|
|
|
|
|
{
|
2026-10-07 23:40:47 +00:00
|
|
|
return TabAlways;
|
2026-10-07 13:49:11 +00:00
|
|
|
}
|
2026-10-07 23:40:47 +00:00
|
|
|
// Reglages qualite video remplaces par les lignes LPVideo* (LPVideoQualitySubsystem).
|
|
|
|
|
if (Widget && (Widget->GetFName() == TEXT("ShadowQuality")
|
|
|
|
|
|| Widget->GetFName() == TEXT("PostProcessQuality")
|
|
|
|
|
|| Widget->GetFName() == TEXT("PostProcessAAQuality")))
|
|
|
|
|
{
|
|
|
|
|
return TabHidden;
|
|
|
|
|
}
|
|
|
|
|
// Noms stables : evite les collisions de mots-cles sur le libelle.
|
|
|
|
|
if (Widget)
|
|
|
|
|
{
|
|
|
|
|
const FName Name = Widget->GetFName();
|
|
|
|
|
if (Name == TEXT("NewAnimationsOnly"))
|
|
|
|
|
{
|
|
|
|
|
return TabGeneral;
|
|
|
|
|
}
|
|
|
|
|
if (Name == TEXT("ShowFPS") || Name == TEXT("ScreenPercentage") || Name == TEXT("FullscreenButton")
|
|
|
|
|
|| Name == TEXT("ToonShading") || Name == TEXT("Censore") || Name == TEXT("CPUSkinning")
|
|
|
|
|
|| Name == TEXT("DisableFurEffect"))
|
|
|
|
|
{
|
|
|
|
|
return TabVideo;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (Widget && (Widget->GetName().StartsWith(TEXT("LPColor")) || Widget->GetName().StartsWith(TEXT("LPVideo"))))
|
2026-10-07 13:49:11 +00:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
2026-10-07 23:40:47 +00:00
|
|
|
if (Text.Contains(TEXT("fps")) || Text.Contains(TEXT("screen percentage")) || Text.Contains(TEXT("shadow"))
|
|
|
|
|
|| 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"))
|
|
|
|
|
|| (Text.Contains(TEXT("quality")) && (Text.Contains(TEXT("shadow")) || Text.Contains(TEXT("aa "))
|
|
|
|
|
|| Text.Contains(TEXT("anti-alias")) || Text.Contains(TEXT("post process")) || Text.Contains(TEXT("pp "))
|
|
|
|
|
|| Text.Contains(TEXT("overall")) || Text.Contains(TEXT("texture")) || Text.Contains(TEXT("effect")))))
|
2026-10-07 13:49:11 +00:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-07 23:40:47 +00:00
|
|
|
void WireMainMenuGI(UUserWidget* Menu, UGameInstance* GI)
|
|
|
|
|
{
|
|
|
|
|
if (!Menu || !GI)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
FObjectPropertyBase* Prop = CastField<FObjectPropertyBase>(Menu->GetClass()->FindPropertyByName(TEXT("GI")));
|
|
|
|
|
if (!Prop || Prop->GetObjectPropertyValue_InContainer(Menu))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!GI->IsA(Prop->PropertyClass))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Prop->SetObjectPropertyValue_InContainer(Menu, GI);
|
|
|
|
|
UE_LOG(LogLifePlay, Display, TEXT("Reglages : MainMenu.GI rattache (evite les spinbox / cases None sur l'ecran titre)"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectCheckBoxes(UWidget* Widget, TArray<UCheckBox*>& Out)
|
|
|
|
|
{
|
|
|
|
|
if (!Widget)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (UCheckBox* Box = Cast<UCheckBox>(Widget))
|
|
|
|
|
{
|
|
|
|
|
Out.Add(Box);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (UUserWidget* User = Cast<UUserWidget>(Widget))
|
|
|
|
|
{
|
|
|
|
|
CollectCheckBoxes(User->GetRootWidget(), Out);
|
|
|
|
|
}
|
|
|
|
|
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
|
|
|
|
|
{
|
|
|
|
|
for (int32 Index = 0; Index < Panel->GetChildrenCount(); ++Index)
|
|
|
|
|
{
|
|
|
|
|
CollectCheckBoxes(Panel->GetChildAt(Index), Out);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CollectSpinBoxes(UWidget* Widget, TArray<USpinBox*>& Out)
|
|
|
|
|
{
|
|
|
|
|
if (!Widget)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (USpinBox* Box = Cast<USpinBox>(Widget))
|
|
|
|
|
{
|
|
|
|
|
Out.Add(Box);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (UUserWidget* User = Cast<UUserWidget>(Widget))
|
|
|
|
|
{
|
|
|
|
|
CollectSpinBoxes(User->GetRootWidget(), Out);
|
|
|
|
|
}
|
|
|
|
|
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
|
|
|
|
|
{
|
|
|
|
|
for (int32 Index = 0; Index < Panel->GetChildrenCount(); ++Index)
|
|
|
|
|
{
|
|
|
|
|
CollectSpinBoxes(Panel->GetChildAt(Index), Out);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TintBrush(FSlateBrush& Brush, const FLinearColor& Tint)
|
|
|
|
|
{
|
|
|
|
|
Brush.TintColor = FSlateColor(Tint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cases et spinboxes BP : style Slate clair → illisible sur fond flou clair.
|
|
|
|
|
// Le curseur Contrast du color grading les revelait sans corriger le style.
|
|
|
|
|
void HardenSettingsControls(UScrollBox* Scroll)
|
|
|
|
|
{
|
|
|
|
|
if (!Scroll)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FCheckBoxStyle CheckStyle = FCoreStyle::Get().GetWidgetStyle<FCheckBoxStyle>("Checkbox");
|
|
|
|
|
const FLinearColor Unchecked(0.08f, 0.08f, 0.08f, 1.f);
|
|
|
|
|
const FLinearColor UncheckedHover(0.18f, 0.18f, 0.18f, 1.f);
|
|
|
|
|
const FLinearColor Checked(0.12f, 0.42f, 0.95f, 1.f);
|
|
|
|
|
const FLinearColor CheckedHover(0.2f, 0.5f, 1.f, 1.f);
|
|
|
|
|
TintBrush(CheckStyle.UncheckedImage, Unchecked);
|
|
|
|
|
TintBrush(CheckStyle.UncheckedHoveredImage, UncheckedHover);
|
|
|
|
|
TintBrush(CheckStyle.UncheckedPressedImage, Unchecked);
|
|
|
|
|
TintBrush(CheckStyle.CheckedImage, Checked);
|
|
|
|
|
TintBrush(CheckStyle.CheckedHoveredImage, CheckedHover);
|
|
|
|
|
TintBrush(CheckStyle.CheckedPressedImage, Checked);
|
|
|
|
|
TintBrush(CheckStyle.UndeterminedImage, Unchecked);
|
|
|
|
|
TintBrush(CheckStyle.UndeterminedHoveredImage, UncheckedHover);
|
|
|
|
|
TintBrush(CheckStyle.UndeterminedPressedImage, Unchecked);
|
|
|
|
|
CheckStyle.BorderBackgroundColor = FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f));
|
|
|
|
|
CheckStyle.ForegroundColor = FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f));
|
|
|
|
|
|
|
|
|
|
FSpinBoxStyle SpinStyle = FCoreStyle::Get().GetWidgetStyle<FSpinBoxStyle>("SpinBox");
|
|
|
|
|
const FLinearColor SpinBg(0.06f, 0.06f, 0.06f, 0.95f);
|
|
|
|
|
const FLinearColor SpinBgHover(0.12f, 0.12f, 0.12f, 0.98f);
|
|
|
|
|
const FLinearColor SpinBgActive(0.16f, 0.16f, 0.16f, 1.f);
|
|
|
|
|
TintBrush(SpinStyle.BackgroundBrush, SpinBg);
|
|
|
|
|
TintBrush(SpinStyle.HoveredBackgroundBrush, SpinBgHover);
|
|
|
|
|
TintBrush(SpinStyle.ActiveBackgroundBrush, SpinBgActive);
|
|
|
|
|
TintBrush(SpinStyle.ActiveFillBrush, FLinearColor(0.2f, 0.45f, 0.9f, 0.85f));
|
|
|
|
|
SpinStyle.ForegroundColor = FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f));
|
|
|
|
|
|
|
|
|
|
TArray<UCheckBox*> Boxes;
|
|
|
|
|
TArray<USpinBox*> Spins;
|
|
|
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
|
|
|
|
{
|
|
|
|
|
CollectCheckBoxes(Scroll->GetChildAt(Index), Boxes);
|
|
|
|
|
CollectSpinBoxes(Scroll->GetChildAt(Index), Spins);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (UCheckBox* Box : Boxes)
|
|
|
|
|
{
|
|
|
|
|
if (!Box)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Box->SetIsEnabled(true);
|
|
|
|
|
Box->SetRenderOpacity(1.f);
|
|
|
|
|
Box->SetWidgetStyle(CheckStyle);
|
|
|
|
|
{
|
|
|
|
|
FWidgetTransform Xform = Box->GetRenderTransform();
|
|
|
|
|
if (FMath::Max(FMath::Abs(Xform.Scale.X), FMath::Abs(Xform.Scale.Y)) < 1.5f)
|
|
|
|
|
{
|
|
|
|
|
Xform.Scale = FVector2D(2.f, 2.f);
|
|
|
|
|
Box->SetRenderTransform(Xform);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (USpinBox* Spin : Spins)
|
|
|
|
|
{
|
|
|
|
|
if (!Spin)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
Spin->SetIsEnabled(true);
|
|
|
|
|
Spin->SetRenderOpacity(1.f);
|
|
|
|
|
Spin->SetWidgetStyle(SpinStyle);
|
|
|
|
|
Spin->SetForegroundColor(FSlateColor(FLinearColor(1.f, 1.f, 1.f, 1.f)));
|
|
|
|
|
FSlateFontInfo Font = Spin->GetFont();
|
|
|
|
|
Font.OutlineSettings.OutlineSize = 2;
|
|
|
|
|
Font.OutlineSettings.bApplyOutlineToDropShadows = true;
|
|
|
|
|
Font.OutlineSettings.OutlineColor = FLinearColor(0.f, 0.f, 0.f, 0.95f);
|
|
|
|
|
if (Font.Size < 18.f)
|
|
|
|
|
{
|
|
|
|
|
Font.Size = 18.f;
|
|
|
|
|
}
|
|
|
|
|
Spin->SetFont(Font);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (UWidget* ShowFPS = [&]() -> UWidget*
|
|
|
|
|
{
|
|
|
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
|
|
|
|
{
|
|
|
|
|
if (UWidget* Child = Scroll->GetChildAt(Index))
|
|
|
|
|
{
|
|
|
|
|
if (Child->GetFName() == TEXT("ShowFPS"))
|
|
|
|
|
{
|
|
|
|
|
return Child;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}())
|
|
|
|
|
{
|
|
|
|
|
ShowFPS->SetIsEnabled(true);
|
|
|
|
|
ShowFPS->SetRenderOpacity(1.f);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-07 13:49:11 +00:00
|
|
|
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);
|
2026-10-07 23:40:47 +00:00
|
|
|
// Chaque frame : le BP Settings peut reforcer Visible sur toutes les lignes entre deux ticks.
|
|
|
|
|
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPSettingsSubsystem::Tick), 0.f);
|
2026-10-07 13:49:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2026-10-07 23:40:47 +00:00
|
|
|
bControlsHardened = false;
|
2026-10-07 13:49:11 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2026-10-07 23:40:47 +00:00
|
|
|
if (UUserWidget* Menu = Scroll->GetTypedOuter<UUserWidget>())
|
|
|
|
|
{
|
|
|
|
|
LPSettingsUi::WireMainMenuGI(Menu, GetGameInstance());
|
|
|
|
|
}
|
2026-10-07 13:49:11 +00:00
|
|
|
EnsureTabs(Scroll);
|
2026-10-07 23:40:47 +00:00
|
|
|
const int32 ChildCount = Scroll->GetChildrenCount();
|
|
|
|
|
if (!bControlsHardened || ChildCount != LastChildCount)
|
2026-10-07 13:49:11 +00:00
|
|
|
{
|
2026-10-07 23:40:47 +00:00
|
|
|
LPSettingsUi::HardenSettingsControls(Scroll);
|
|
|
|
|
bControlsHardened = true;
|
|
|
|
|
LastChildCount = ChildCount;
|
2026-10-07 13:49:11 +00:00
|
|
|
}
|
2026-10-07 23:40:47 +00:00
|
|
|
ApplyRows();
|
2026-10-07 13:49:11 +00:00
|
|
|
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);
|
2026-10-07 23:40:47 +00:00
|
|
|
// -1 : toujours visible (BackButton) ; -2 : toujours replie.
|
|
|
|
|
const bool bShow = Category == LPSettingsUi::TabAlways || (Category != LPSettingsUi::TabHidden && ActiveTab != LPSettingsUi::TabKeyboard && Category == ActiveTab);
|
2026-10-07 13:49:11 +00:00
|
|
|
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); }
|