Files
ZMMO/Source/ZMMO/Game/UI/Widgets/UIProgressBar_Base.cpp
Mateus Rodrigues cda5fea776 feat(admin-tools): consumidor client do painel debug (F8 + UZeusAOIComponent)
- UZeusAOIComponent (Game/Network): componente de gameplay do player local com
  plus de debug. Overlays via DrawDebug* (esfera AOI real; spawn/cell/handoff
  placeholders) dirigidos pela UI via IZeusAOIDebugTarget + console vars. Estado
  persiste no componente entre aberturas do menu (IsOverlayEnabled).
- AZeusCharacter: anexa o componente + abre/fecha o painel no F8 (UIOnly trava o
  jogo; Esc/F8 fecham); LoadClass lazy do painel no content do PLUGIN
  (/ZeusAdminTools/UI/WBP_AdminToolsAIO).
- ZMMO.Build.cs: depende de ZeusAdminToolsRuntime.
- UIProgressBar_Base: rename EaseOutCubic -> EaseOutCubicPB (fix unity-build).
- ZMMO.uproject: remove entrada NwiroIntegrationKit.

A UI e o C++ do plugin ZeusAdminTools vivem no repo Server (plugin autocontido).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 16:19:37 -03:00

762 lines
23 KiB
C++

#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 EaseOutCubicPB(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<UZeusThemeSubsystem>())
{
return Theme->GetActiveUIStyle();
}
}
}
// Design-time fallback: lê DT_UI_Styles row "Default" direto do disk.
if (const UDataTable* DT = LoadObject<UDataTable>(nullptr,
TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles")))
{
if (const FUIStyleRow* Row = DT->FindRow<FUIStyleRow>(
FName(TEXT("Default")), TEXT("UIProgressBarDesign"), false))
{
return Row->Style;
}
}
return FUIStyle();
}
TArray<FString> CollectVariantOptions()
{
TArray<FString> Options;
Options.Add(FString()); // entrada vazia = sem theme
const UDataTable* DT = LoadObject<UDataTable>(nullptr,
TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles"));
if (!DT) return Options;
const FUIStyleRow* Row = DT->FindRow<FUIStyleRow>(
FName(TEXT("Default")), TEXT("UIProgressBarGetOptions"), false);
if (!Row) return Options;
for (const TPair<FName, FUIStyleProgressBarVariant>& 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<UZeusThemeSubsystem>())
{
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<UZeusThemeSubsystem>())
{
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, EaseOutCubicPB(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, EaseOutCubicPB(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<UMaterialInterface>(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<UMaterialInterface>(BackgroundImage->GetBrush().GetResourceObject()))
{
BackgroundMID = UMaterialInstanceDynamic::Create(Mat, this);
BackgroundImage->SetBrushFromMaterial(BackgroundMID);
ApplyBrushStyle();
}
}
if (TrackGridImage && !TrackGridMID)
{
if (UMaterialInterface* Mat = Cast<UMaterialInterface>(TrackGridImage->GetBrush().GetResourceObject()))
{
TrackGridMID = UMaterialInstanceDynamic::Create(Mat, this);
TrackGridImage->SetBrushFromMaterial(TrackGridMID);
ApplyBrushStyle();
}
}
if (ShimmerImage && !ShimmerMID)
{
if (UMaterialInterface* Mat = Cast<UMaterialInterface>(ShimmerImage->GetBrush().GetResourceObject()))
{
ShimmerMID = UMaterialInstanceDynamic::Create(Mat, this);
ShimmerImage->SetBrushFromMaterial(ShimmerMID);
ApplyBrushStyle();
}
}
if (EdgeImage && !EdgeMID)
{
if (UMaterialInterface* Mat = Cast<UMaterialInterface>(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<UOverlaySlot>(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<FString> UUIProgressBar_Base::GetProgressBarVariantOptions() const
{
return CollectVariantOptions();
}