#include "UISpinner_Base.h" #include "ZMMOThemeSubsystem.h" #include "Engine/GameInstance.h" #include "Engine/DataTable.h" #include "Components/CircularThrobber.h" #include "UI/UIStyleRow.h" namespace { // Mesmo padrão de UUIPanel_Base: runtime usa o tema ativo; design-time // carrega a row "Default" de DT_UI_Styles para o Designer ver igual. FUIStyle ResolveSpinnerStyle(const UUserWidget* Widget, const FUIStyle& Fallback) { if (Widget) { if (const UGameInstance* GI = Widget->GetGameInstance()) { if (const UZMMOThemeSubsystem* Theme = GI->GetSubsystem()) { return Theme->GetActiveUIStyle(); } } } // Design-time relê o DT a cada chamada: editar o DT_UI_Styles e // RECOMPILAR o WBP já reflete (sem reiniciar o editor). FUIStyle DesignStyle; bool bHas = false; if (const UDataTable* DT = LoadObject(nullptr, TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles"))) { if (const FUIStyleRow* Row = DT->FindRow( FName(TEXT("Default")), TEXT("UISpinnerDesign"), false)) { DesignStyle = Row->Style; bHas = true; } } return bHas ? DesignStyle : Fallback; } } static FUIStyleSpinnerVariant ResolveSpinnerVariant(const FUIStyleSpinner& Sp, FName VariantName) { static const FUIStyleSpinner Defaults; FUIStyleSpinnerVariant V; if (const FUIStyleSpinnerColors* E = Sp.Colors.Find(VariantName)) { V.Colors = *E; } else if (const FUIStyleSpinnerColors* E2 = Defaults.Colors.Find(VariantName)) { V.Colors = *E2; } else { V.Colors = Defaults.Colors.FindRef(TEXT("Default")); } if (const FUIStyleSpinnerLayout* E = Sp.Layouts.Find(VariantName)) { V.Layout = *E; } else if (const FUIStyleSpinnerLayout* E2 = Defaults.Layouts.Find(VariantName)) { V.Layout = *E2; } else { V.Layout = Defaults.Layouts.FindRef(TEXT("Default")); } return V; } TArray UUISpinner_Base::GetVariantOptions() const { TArray Options; Options.Add(TEXT("Default")); if (const UDataTable* DT = LoadObject(nullptr, TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles"))) { if (const FUIStyleRow* Row = DT->FindRow( FName(TEXT("Default")), TEXT("UISpinnerVariantOptions"), false)) { for (const TPair& P : Row->Style.Spinner.Colors) { Options.AddUnique(P.Key.ToString()); } for (const TPair& P : Row->Style.Spinner.Layouts) { Options.AddUnique(P.Key.ToString()); } } } return Options; } void UUISpinner_Base::RefreshUIStyle() { const FUIStyle Fallback; const FUIStyle AS = ResolveSpinnerStyle(this, Fallback); const FUIStyleSpinnerVariant V = ResolveSpinnerVariant(AS.Spinner, Variant); if (Throbber) { Throbber->SetNumberOfPieces(FMath::Max(1, V.Layout.NumberOfPieces)); Throbber->SetPeriod(FMath::Max(0.05f, V.Layout.Period)); Throbber->SetRadius(V.Layout.Radius); } BP_ApplySpinnerStyle(V); } void UUISpinner_Base::NativePreConstruct() { Super::NativePreConstruct(); RefreshUIStyle(); } void UUISpinner_Base::NativeConstruct() { Super::NativeConstruct(); if (!bThemeBound) { if (const UGameInstance* GI = GetGameInstance()) { if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem()) { Theme->OnThemeChanged.AddDynamic(this, &UUISpinner_Base::HandleThemeChanged); bThemeBound = true; } } } RefreshUIStyle(); } void UUISpinner_Base::NativeDestruct() { if (bThemeBound) { if (const UGameInstance* GI = GetGameInstance()) { if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem()) { Theme->OnThemeChanged.RemoveDynamic(this, &UUISpinner_Base::HandleThemeChanged); } } bThemeBound = false; } Super::NativeDestruct(); } void UUISpinner_Base::HandleThemeChanged(FName /*NewThemeId*/) { RefreshUIStyle(); }