#include "UIProgressBar_Base.h" #include "Components/Image.h" #include "Components/OverlaySlot.h" #include "Engine/DataTable.h" #include "Engine/GameInstance.h" #include "Materials/MaterialInstanceDynamic.h" #include "Materials/MaterialInterface.h" #include "Styling/SlateBrush.h" #include "Styling/SlateTypes.h" #include "UI/UIStyleRow.h" #include "UI/UIStyleTokens.h" #include "ZeusThemeSubsystem.h" namespace { constexpr float MinAnimSeconds = 0.001f; // Fill material params static const FName P_PrimaryLevel("PrimaryLevel"); static const FName P_SecondaryLevel("SecondaryLevel"); static const FName P_PrimaryColour("PrimaryColour"); static const FName P_PrimaryColourBottom("PrimaryColourBottom"); static const FName P_SecondaryColour("SecondaryColour"); static const FName P_SecondaryColourBottom("SecondaryColourBottom"); static const FName P_EmptyColour("EmptyColour"); static const FName P_EnableGradient("EnableGradient"); static const FName P_GradientSplit("GradientSplit"); // BG material params static const FName P_BackgroundColour("BackgroundColour"); // TrackGrid material params static const FName P_GridColour("GridColour"); static const FName P_GridDivisions("GridDivisions"); static const FName P_GridLineThickness("GridLineThickness"); // Shimmer material params static const FName P_ShimmerColour("ShimmerColour"); static const FName P_ShimmerWidth("ShimmerWidth"); static const FName P_ShimmerSpeed("ShimmerSpeed"); static const FName P_ShimmerSoftness("ShimmerSoftness"); // Edge material params static const FName P_EdgeColour("EdgeColour"); static const FName P_EdgeWidth("EdgeWidth"); static const FName P_EdgeGlowWidth("EdgeGlowWidth"); static const FName P_EdgeGlowIntensity("EdgeGlowIntensity"); FORCEINLINE float EaseOutCubic(float Alpha) { return 1.f - FMath::Pow(1.f - Alpha, 3.f); } /** Resolve a FUIStyle ativa — runtime via ThemeSubsystem, design-time via DT direto. */ FUIStyle ResolveProgressBarStyle(const UUserWidget* Widget) { if (Widget) { if (const UGameInstance* GI = Widget->GetGameInstance()) { if (const UZeusThemeSubsystem* Theme = GI->GetSubsystem()) { return Theme->GetActiveUIStyle(); } } } // Design-time fallback: lê DT_UI_Styles row "Default" direto do disk. 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("UIProgressBarDesign"), false)) { return Row->Style; } } return FUIStyle(); } TArray CollectVariantOptions() { TArray Options; Options.Add(FString()); // entrada vazia = sem theme const UDataTable* DT = LoadObject(nullptr, TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles")); if (!DT) return Options; const FUIStyleRow* Row = DT->FindRow( FName(TEXT("Default")), TEXT("UIProgressBarGetOptions"), false); if (!Row) return Options; for (const TPair& Pair : Row->Style.ProgressBar.Variants) { Options.Add(Pair.Key.ToString()); } Options.Sort(); return Options; } } void UUIProgressBar_Base::NativePreConstruct() { Super::NativePreConstruct(); CurrentPrimaryLevel = InitialPrimaryLevel; TargetPrimaryLevel = InitialPrimaryLevel; PrimaryStart = InitialPrimaryLevel; PrimaryElapsed = 0.f; bAnimatingPrimary = false; CurrentSecondaryLevel = InitialSecondaryLevel; TargetSecondaryLevel = InitialSecondaryLevel; SecondaryStart = InitialSecondaryLevel; SecondaryElapsed = 0.f; bAnimatingSecondary = false; if (bUseTheme) { RefreshUIStyle(); } else { ApplyBrushStyle(); EnsureMIDs(); ApplyMaterialOverrides(); } ApplyPrimaryToMID(CurrentPrimaryLevel); ApplySecondaryToMID(CurrentSecondaryLevel); } void UUIProgressBar_Base::NativeConstruct() { Super::NativeConstruct(); if (!bThemeBound) { if (const UGameInstance* GI = GetGameInstance()) { if (UZeusThemeSubsystem* Theme = GI->GetSubsystem()) { Theme->OnThemeChanged.AddDynamic(this, &UUIProgressBar_Base::HandleThemeChanged); bThemeBound = true; } } } if (bUseTheme) { RefreshUIStyle(); } else { ApplyBrushStyle(); EnsureMIDs(); ApplyMaterialOverrides(); } ApplyPrimaryToMID(CurrentPrimaryLevel); ApplySecondaryToMID(CurrentSecondaryLevel); } void UUIProgressBar_Base::NativeDestruct() { if (bThemeBound) { if (const UGameInstance* GI = GetGameInstance()) { if (UZeusThemeSubsystem* Theme = GI->GetSubsystem()) { Theme->OnThemeChanged.RemoveDynamic(this, &UUIProgressBar_Base::HandleThemeChanged); } } bThemeBound = false; } Super::NativeDestruct(); } void UUIProgressBar_Base::HandleThemeChanged(FName /*NewThemeId*/) { if (bUseTheme) { RefreshUIStyle(); } } void UUIProgressBar_Base::NativeTick(const FGeometry& MyGeometry, float InDeltaTime) { Super::NativeTick(MyGeometry, InDeltaTime); if (!bAnimatingPrimary && !bAnimatingSecondary) { return; } if (bAnimatingPrimary) { PrimaryElapsed += InDeltaTime; const float Duration = FMath::Max(PrimaryAnimationSeconds, MinAnimSeconds); const float Alpha = FMath::Clamp(PrimaryElapsed / Duration, 0.f, 1.f); CurrentPrimaryLevel = FMath::Lerp(PrimaryStart, TargetPrimaryLevel, EaseOutCubic(Alpha)); ApplyPrimaryToMID(CurrentPrimaryLevel); if (Alpha >= 1.f) { CurrentPrimaryLevel = TargetPrimaryLevel; ApplyPrimaryToMID(CurrentPrimaryLevel); bAnimatingPrimary = false; } } if (bAnimatingSecondary) { SecondaryElapsed += InDeltaTime; const float Duration = FMath::Max(SecondaryAnimationSeconds, MinAnimSeconds); const float Alpha = FMath::Clamp(SecondaryElapsed / Duration, 0.f, 1.f); CurrentSecondaryLevel = FMath::Lerp(SecondaryStart, TargetSecondaryLevel, EaseOutCubic(Alpha)); ApplySecondaryToMID(CurrentSecondaryLevel); if (Alpha >= 1.f) { CurrentSecondaryLevel = TargetSecondaryLevel; ApplySecondaryToMID(CurrentSecondaryLevel); bAnimatingSecondary = false; } } } void UUIProgressBar_Base::SetTargetPrimaryLevel(float Primary01) { const float Clamped = FMath::Clamp(Primary01, 0.f, 1.f); if (PrimaryAnimationSeconds <= MinAnimSeconds) { SetPrimaryLevelImmediate(Clamped); return; } if (FMath::IsNearlyEqual(Clamped, CurrentPrimaryLevel, KINDA_SMALL_NUMBER) && FMath::IsNearlyEqual(Clamped, TargetPrimaryLevel, KINDA_SMALL_NUMBER)) { return; } TargetPrimaryLevel = Clamped; PrimaryStart = CurrentPrimaryLevel; PrimaryElapsed = 0.f; bAnimatingPrimary = true; } void UUIProgressBar_Base::SetPrimaryLevelImmediate(float Primary01) { const float Clamped = FMath::Clamp(Primary01, 0.f, 1.f); CurrentPrimaryLevel = Clamped; TargetPrimaryLevel = Clamped; PrimaryStart = Clamped; PrimaryElapsed = 0.f; bAnimatingPrimary = false; ApplyPrimaryToMID(CurrentPrimaryLevel); } void UUIProgressBar_Base::SetTargetSecondaryLevel(float Sec01) { const float Clamped = FMath::Clamp(Sec01, 0.f, 1.f); if (SecondaryAnimationSeconds <= MinAnimSeconds) { SetSecondaryLevelImmediate(Clamped); return; } if (FMath::IsNearlyEqual(Clamped, CurrentSecondaryLevel, KINDA_SMALL_NUMBER) && FMath::IsNearlyEqual(Clamped, TargetSecondaryLevel, KINDA_SMALL_NUMBER)) { return; } TargetSecondaryLevel = Clamped; SecondaryStart = CurrentSecondaryLevel; SecondaryElapsed = 0.f; bAnimatingSecondary = true; } void UUIProgressBar_Base::SetSecondaryLevelImmediate(float Sec01) { const float Clamped = FMath::Clamp(Sec01, 0.f, 1.f); CurrentSecondaryLevel = Clamped; TargetSecondaryLevel = Clamped; SecondaryStart = Clamped; SecondaryElapsed = 0.f; bAnimatingSecondary = false; ApplySecondaryToMID(CurrentSecondaryLevel); } void UUIProgressBar_Base::SetDrawStyle(EUIProgressBarStyle InStyle) { DrawStyle = InStyle; ApplyBrushStyle(); } void UUIProgressBar_Base::SetCornerRadius(float RadiusPixels) { CornerRadius = FMath::Clamp(RadiusPixels, 0.f, 100.f); ApplyBrushStyle(); } void UUIProgressBar_Base::SetBorderVisible(bool bVisible) { bShowBorder = bVisible; ApplyBrushStyle(); } void UUIProgressBar_Base::SetBorderColour(FLinearColor Color) { BorderColour = Color; bShowBorder = true; ApplyBrushStyle(); } void UUIProgressBar_Base::SetBorderWidth(float WidthPixels) { BorderWidth = FMath::Clamp(WidthPixels, 0.f, 10.f); ApplyBrushStyle(); } void UUIProgressBar_Base::SetPrimaryColour(FLinearColor Color) { PrimaryColour = Color; bOverridePrimaryColour = true; if (FillMID) FillMID->SetVectorParameterValue(P_PrimaryColour, Color); } void UUIProgressBar_Base::SetPrimaryColourBottom(FLinearColor Color) { PrimaryColourBottom = Color; bOverridePrimaryColourBottom = true; if (FillMID) FillMID->SetVectorParameterValue(P_PrimaryColourBottom, Color); } void UUIProgressBar_Base::SetSecondaryColour(FLinearColor Color) { SecondaryColour = Color; bOverrideSecondaryColour = true; if (FillMID) FillMID->SetVectorParameterValue(P_SecondaryColour, Color); } void UUIProgressBar_Base::SetSecondaryColourBottom(FLinearColor Color) { SecondaryColourBottom = Color; bOverrideSecondaryColourBottom = true; if (FillMID) FillMID->SetVectorParameterValue(P_SecondaryColourBottom, Color); } void UUIProgressBar_Base::SetEmptyColour(FLinearColor Color) { EmptyColour = Color; bOverrideEmptyColour = true; if (FillMID) FillMID->SetVectorParameterValue(P_EmptyColour, Color); } void UUIProgressBar_Base::SetBackgroundColour(FLinearColor Color) { BackgroundColour = Color; bOverrideBackgroundColour = true; if (BackgroundMID) BackgroundMID->SetVectorParameterValue(P_BackgroundColour, Color); } void UUIProgressBar_Base::SetTrackGridVisible(bool bVisible) { bShowTrackGrid = bVisible; if (TrackGridImage) { TrackGridImage->SetVisibility(bVisible ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed); } } void UUIProgressBar_Base::SetGridColour(FLinearColor Color) { GridColour = Color; bOverrideGridColour = true; if (TrackGridMID) TrackGridMID->SetVectorParameterValue(P_GridColour, Color); } void UUIProgressBar_Base::SetGridDivisions(float Divisions) { GridDivisions = FMath::Clamp(Divisions, 2.f, 50.f); bOverrideGridDivisions = true; if (TrackGridMID) TrackGridMID->SetScalarParameterValue(P_GridDivisions, GridDivisions); } void UUIProgressBar_Base::SetGridLineThickness(float Thickness) { GridLineThickness = FMath::Clamp(Thickness, 0.001f, 0.2f); bOverrideGridLineThickness = true; if (TrackGridMID) TrackGridMID->SetScalarParameterValue(P_GridLineThickness, GridLineThickness); } void UUIProgressBar_Base::SetEdgeVisible(bool bVisible) { bShowEdge = bVisible; UpdateEdgeVisibility(); } void UUIProgressBar_Base::SetEdgeColour(FLinearColor Color) { EdgeColour = Color; bOverrideEdgeColour = true; if (EdgeMID) EdgeMID->SetVectorParameterValue(P_EdgeColour, Color); } void UUIProgressBar_Base::SetEdgeWidth(float Width01) { EdgeWidth = FMath::Clamp(Width01, 0.001f, 0.1f); bOverrideEdgeWidth = true; if (EdgeMID) EdgeMID->SetScalarParameterValue(P_EdgeWidth, EdgeWidth); } void UUIProgressBar_Base::SetEdgeGlowWidth(float GlowWidth01) { EdgeGlowWidth = FMath::Clamp(GlowWidth01, 0.f, 0.2f); bOverrideEdgeGlowWidth = true; if (EdgeMID) EdgeMID->SetScalarParameterValue(P_EdgeGlowWidth, EdgeGlowWidth); } void UUIProgressBar_Base::SetEdgeGlowIntensity(float Intensity01) { EdgeGlowIntensity = FMath::Clamp(Intensity01, 0.f, 1.f); bOverrideEdgeGlowIntensity = true; if (EdgeMID) EdgeMID->SetScalarParameterValue(P_EdgeGlowIntensity, EdgeGlowIntensity); } void UUIProgressBar_Base::SetShimmerVisible(bool bVisible) { bShowShimmer = bVisible; if (ShimmerImage) { ShimmerImage->SetVisibility(bVisible ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed); } } void UUIProgressBar_Base::SetShimmerColour(FLinearColor Color) { ShimmerColour = Color; bOverrideShimmerColour = true; if (ShimmerMID) ShimmerMID->SetVectorParameterValue(P_ShimmerColour, Color); } void UUIProgressBar_Base::SetShimmerWidth(float Width01) { ShimmerWidth = FMath::Clamp(Width01, 0.05f, 1.f); bOverrideShimmerWidth = true; if (ShimmerMID) ShimmerMID->SetScalarParameterValue(P_ShimmerWidth, ShimmerWidth); } void UUIProgressBar_Base::SetShimmerSpeed(float Speed) { ShimmerSpeed = FMath::Clamp(Speed, 0.01f, 5.f); bOverrideShimmerSpeed = true; if (ShimmerMID) ShimmerMID->SetScalarParameterValue(P_ShimmerSpeed, ShimmerSpeed); } void UUIProgressBar_Base::SetShimmerSoftness(float Softness) { ShimmerSoftness = FMath::Clamp(Softness, 0.5f, 8.f); bOverrideShimmerSoftness = true; if (ShimmerMID) ShimmerMID->SetScalarParameterValue(P_ShimmerSoftness, ShimmerSoftness); } void UUIProgressBar_Base::SetGradientEnabled(bool bEnabled) { bEnableGradient = bEnabled; bOverrideEnableGradient = true; if (FillMID) FillMID->SetScalarParameterValue(P_EnableGradient, bEnabled ? 1.f : 0.f); } void UUIProgressBar_Base::SetGradientSplit(float Split01) { GradientSplit = FMath::Clamp(Split01, 0.f, 1.f); bOverrideGradientSplit = true; if (FillMID) FillMID->SetScalarParameterValue(P_GradientSplit, GradientSplit); } void UUIProgressBar_Base::ShowHealPreview(float TargetPct, FLinearColor PreviewColor) { SetSecondaryColour(PreviewColor); SetTargetSecondaryLevel(TargetPct); } void UUIProgressBar_Base::ShowDamageLag(float OldPct, float NewPct, FLinearColor LagColor) { SetSecondaryColour(LagColor); SetSecondaryLevelImmediate(OldPct); SetPrimaryLevelImmediate(NewPct); SetTargetSecondaryLevel(NewPct); } void UUIProgressBar_Base::ShowBuffer(float BufferPct, FLinearColor BufferColor) { SetSecondaryColour(BufferColor); SetTargetSecondaryLevel(FMath::Clamp(CurrentPrimaryLevel + BufferPct, 0.f, 1.f)); } void UUIProgressBar_Base::ClearSecondary() { SetTargetSecondaryLevel(0.f); } void UUIProgressBar_Base::EnsureMIDs() { if (FillImage && !FillMID) { if (UMaterialInterface* Mat = Cast(FillImage->GetBrush().GetResourceObject())) { FillMID = UMaterialInstanceDynamic::Create(Mat, this); FillImage->SetBrushFromMaterial(FillMID); // SetBrushFromMaterial reseta DrawAs e OutlineSettings — re-aplica. ApplyBrushStyle(); } } if (BackgroundImage && !BackgroundMID) { if (UMaterialInterface* Mat = Cast(BackgroundImage->GetBrush().GetResourceObject())) { BackgroundMID = UMaterialInstanceDynamic::Create(Mat, this); BackgroundImage->SetBrushFromMaterial(BackgroundMID); ApplyBrushStyle(); } } if (TrackGridImage && !TrackGridMID) { if (UMaterialInterface* Mat = Cast(TrackGridImage->GetBrush().GetResourceObject())) { TrackGridMID = UMaterialInstanceDynamic::Create(Mat, this); TrackGridImage->SetBrushFromMaterial(TrackGridMID); ApplyBrushStyle(); } } if (ShimmerImage && !ShimmerMID) { if (UMaterialInterface* Mat = Cast(ShimmerImage->GetBrush().GetResourceObject())) { ShimmerMID = UMaterialInstanceDynamic::Create(Mat, this); ShimmerImage->SetBrushFromMaterial(ShimmerMID); ApplyBrushStyle(); } } if (EdgeImage && !EdgeMID) { if (UMaterialInterface* Mat = Cast(EdgeImage->GetBrush().GetResourceObject())) { EdgeMID = UMaterialInstanceDynamic::Create(Mat, this); EdgeImage->SetBrushFromMaterial(EdgeMID); ApplyBrushStyle(); } } } void UUIProgressBar_Base::ApplyMaterialOverrides() { if (FillMID) { if (bOverridePrimaryColour) FillMID->SetVectorParameterValue(P_PrimaryColour, PrimaryColour); if (bOverridePrimaryColourBottom) FillMID->SetVectorParameterValue(P_PrimaryColourBottom, PrimaryColourBottom); if (bOverrideSecondaryColour) FillMID->SetVectorParameterValue(P_SecondaryColour, SecondaryColour); if (bOverrideSecondaryColourBottom) FillMID->SetVectorParameterValue(P_SecondaryColourBottom, SecondaryColourBottom); if (bOverrideEmptyColour) FillMID->SetVectorParameterValue(P_EmptyColour, EmptyColour); if (bOverrideEnableGradient) FillMID->SetScalarParameterValue(P_EnableGradient, bEnableGradient ? 1.f : 0.f); if (bOverrideGradientSplit) FillMID->SetScalarParameterValue(P_GradientSplit, GradientSplit); } if (BackgroundMID) { if (bOverrideBackgroundColour) BackgroundMID->SetVectorParameterValue(P_BackgroundColour, BackgroundColour); } if (TrackGridMID) { if (bOverrideGridColour) TrackGridMID->SetVectorParameterValue(P_GridColour, GridColour); if (bOverrideGridDivisions) TrackGridMID->SetScalarParameterValue(P_GridDivisions, GridDivisions); if (bOverrideGridLineThickness) TrackGridMID->SetScalarParameterValue(P_GridLineThickness, GridLineThickness); } if (ShimmerMID) { if (bOverrideShimmerColour) ShimmerMID->SetVectorParameterValue(P_ShimmerColour, ShimmerColour); if (bOverrideShimmerWidth) ShimmerMID->SetScalarParameterValue(P_ShimmerWidth, ShimmerWidth); if (bOverrideShimmerSpeed) ShimmerMID->SetScalarParameterValue(P_ShimmerSpeed, ShimmerSpeed); if (bOverrideShimmerSoftness) ShimmerMID->SetScalarParameterValue(P_ShimmerSoftness, ShimmerSoftness); } if (EdgeMID) { if (bOverrideEdgeColour) EdgeMID->SetVectorParameterValue(P_EdgeColour, EdgeColour); if (bOverrideEdgeWidth) EdgeMID->SetScalarParameterValue(P_EdgeWidth, EdgeWidth); if (bOverrideEdgeGlowWidth) EdgeMID->SetScalarParameterValue(P_EdgeGlowWidth, EdgeGlowWidth); if (bOverrideEdgeGlowIntensity) EdgeMID->SetScalarParameterValue(P_EdgeGlowIntensity, EdgeGlowIntensity); } // Visibilidade dos widgets opcionais if (TrackGridImage) { TrackGridImage->SetVisibility(bShowTrackGrid ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed); } UpdateEdgeVisibility(); if (ShimmerImage) { ShimmerImage->SetVisibility(bShowShimmer ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed); } } void UUIProgressBar_Base::ApplyBrushStyle() { const float InsetForShimmer = bShowBorder ? FMath::Max(BorderWidth, 0.f) : 0.f; auto Apply = [this](UImage* Img, bool bAllowBorder, float RadiusInset) { if (!Img) { return; } FSlateBrush B = Img->GetBrush(); B.DrawAs = (DrawStyle == EUIProgressBarStyle::Rounded) ? ESlateBrushDrawType::RoundedBox : ESlateBrushDrawType::Image; FSlateBrushOutlineSettings Outline = B.OutlineSettings; const float R = FMath::Max(CornerRadius - RadiusInset, 0.f); Outline.CornerRadii = FVector4(R, R, R, R); Outline.RoundingType = ESlateBrushRoundingType::FixedRadius; if (bAllowBorder && bShowBorder) { Outline.Color = FSlateColor(BorderColour); Outline.Width = FMath::Max(BorderWidth, 0.f); } else { Outline.Color = FSlateColor(FLinearColor::Transparent); Outline.Width = 0.f; } B.OutlineSettings = Outline; Img->SetBrush(B); }; // Borda só no BG. Shimmer ganha inset = BorderWidth (padding no slot + corner reduzido) // pra não passar por cima do outline do BG. Demais widgets sem inset. Apply(BackgroundImage, /*bAllowBorder=*/true, 0.f); Apply(TrackGridImage, /*bAllowBorder=*/false, 0.f); Apply(FillImage, /*bAllowBorder=*/false, 0.f); Apply(EdgeImage, /*bAllowBorder=*/false, 0.f); Apply(ShimmerImage, /*bAllowBorder=*/false, InsetForShimmer); if (ShimmerImage) { if (UOverlaySlot* OS = Cast(ShimmerImage->Slot)) { OS->SetPadding(FMargin(InsetForShimmer)); } } } void UUIProgressBar_Base::ApplyPrimaryToMID(float Value) { if (FillMID) { FillMID->SetScalarParameterValue(P_PrimaryLevel, Value); } // Edge acompanha o nível Primary (posição da linha = PrimaryLevel) if (EdgeMID) { EdgeMID->SetScalarParameterValue(P_PrimaryLevel, Value); } UpdateEdgeVisibility(); } void UUIProgressBar_Base::UpdateEdgeVisibility() { if (!EdgeImage) { return; } if (!bShowEdge) { EdgeImage->SetVisibility(ESlateVisibility::Collapsed); return; } // Auto-hide quando Primary está nos extremos (0 ou 1) — Edge encostaria na borda. const bool bAtExtreme = (CurrentPrimaryLevel <= 0.f) || (CurrentPrimaryLevel >= 1.f); EdgeImage->SetVisibility(bAtExtreme ? ESlateVisibility::Collapsed : ESlateVisibility::HitTestInvisible); } void UUIProgressBar_Base::ApplySecondaryToMID(float Value) { if (FillMID) { FillMID->SetScalarParameterValue(P_SecondaryLevel, Value); } } // ===================================================================== // Theme integration (bUseTheme + Variant) // ===================================================================== void UUIProgressBar_Base::RefreshUIStyle() { if (!bUseTheme || Variant.IsNone()) { // Fallback: comportamento manual. ApplyBrushStyle(); EnsureMIDs(); ApplyMaterialOverrides(); return; } const FUIStyle ActiveStyle = ResolveProgressBarStyle(this); const FUIStyleProgressBarVariant* V = ActiveStyle.ProgressBar.Variants.Find(Variant); if (!V) { // Variante não existe no DT — fallback manual. ApplyBrushStyle(); EnsureMIDs(); ApplyMaterialOverrides(); return; } ApplyThemeVariant(*V); } void UUIProgressBar_Base::ApplyThemeVariant(const FUIStyleProgressBarVariant& V) { // Style — copia pros campos do widget e re-aplica brush. DrawStyle = V.DrawStyle; CornerRadius = V.CornerRadius; bShowBorder = V.bShowBorder; BorderColour = V.BorderColour; BorderWidth = V.BorderWidth; // Toggles de efeito bShowTrackGrid = V.bShowTrackGrid; bShowEdge = V.bShowEdge; bShowShimmer = V.bShowShimmer; // Troca materiais nos brushes quando definidos. Reseta MIDs cacheados pra // que EnsureMIDs() pegue o material novo na próxima chamada. auto AssignMaterial = [](UImage* Img, UMaterialInterface* Mat) { if (!Img || !Mat) return; FSlateBrush B = Img->GetBrush(); if (B.GetResourceObject() != Mat) { B.SetResourceObject(Mat); B.DrawAs = ESlateBrushDrawType::Image; // reset; ApplyBrushStyle re-aplica Img->SetBrush(B); } }; if (V.FillMaterial) { AssignMaterial(FillImage, V.FillMaterial); FillMID = nullptr; } if (V.BackgroundMaterial) { AssignMaterial(BackgroundImage, V.BackgroundMaterial); BackgroundMID = nullptr; } if (V.TrackGridMaterial) { AssignMaterial(TrackGridImage, V.TrackGridMaterial); TrackGridMID = nullptr; } if (V.EdgeMaterial) { AssignMaterial(EdgeImage, V.EdgeMaterial); EdgeMID = nullptr; } if (V.ShimmerMaterial) { AssignMaterial(ShimmerImage, V.ShimmerMaterial); ShimmerMID = nullptr; } ApplyBrushStyle(); EnsureMIDs(); // Quando vem do tema, ignora os bOverride* individuais — variante já é a // fonte da verdade. Cores são definidas pela MI atribuída ao brush. // Aplica visibility dos toggles if (TrackGridImage) TrackGridImage->SetVisibility(bShowTrackGrid ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed); if (ShimmerImage) ShimmerImage->SetVisibility(bShowShimmer ? ESlateVisibility::HitTestInvisible : ESlateVisibility::Collapsed); UpdateEdgeVisibility(); } TArray UUIProgressBar_Base::GetProgressBarVariantOptions() const { return CollectVariantOptions(); }