feat(ui/progressbar): integracao com DT_UI_Styles (FUIStyleProgressBar multi-map + Variant)

FUIStyleProgressBar vira multi-map Hyper-style: TMap<FName, FUIStyleProgressBarVariant>
indexado por variante (HP/MP/XP/Cast/...). Cada variante carrega materiais por
layer (Fill/BG/TrackGrid/Edge/Shimmer) + style (DrawStyle/CornerRadius/Border) +
toggles de efeito.

UUIProgressBar_Base ganha bUseTheme + Variant (dropdown via meta=GetOptions
resolvendo o DT) + RefreshUIStyle() que aplica a variante via ThemeSubsystem
(runtime) ou DT direto (design-time), espelhando o padrao do UUIPanel_Base.
HandleThemeChanged reaplica em troca de tema.

EUIProgressBarStyle movido de UIProgressBar_Base.h para UIStyleTypes.h (usado
pela struct do DT).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-28 00:33:43 -03:00
parent 88eb20eefa
commit c9492a3910
6 changed files with 295 additions and 33 deletions

View File

@@ -374,29 +374,78 @@ struct ZMMO_API FUIStyleBorders
float RuleSoftThickness = 1.f;
};
/**
* Variante completa de ProgressBar: materiais por layer (Fill/BG/Track/Edge/Shimmer)
* + parametros visuais (DrawStyle, CornerRadius, Border) + toggles de efeito.
*
* Material nulo = nao sobrescreve o brush do WBP (usa o que esta atribuido la).
* Aplicada pelo UUIProgressBar_Base quando bUseTheme=true via Variant FName.
*/
USTRUCT(BlueprintType)
struct ZMMO_API FUIStyleProgressBarVariant
{
GENERATED_BODY()
// ---- Materiais (opcionais; nullptr = mantem brush do WBP) ----
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Materials")
TObjectPtr<UMaterialInterface> FillMaterial;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Materials")
TObjectPtr<UMaterialInterface> BackgroundMaterial;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Materials")
TObjectPtr<UMaterialInterface> TrackGridMaterial;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Materials")
TObjectPtr<UMaterialInterface> EdgeMaterial;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Materials")
TObjectPtr<UMaterialInterface> ShimmerMaterial;
// ---- Style (forma + bordas) ----
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Style")
EUIProgressBarStyle DrawStyle = EUIProgressBarStyle::Rounded;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Style",
meta = (ClampMin = "0", ClampMax = "100"))
float CornerRadius = 8.f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Style")
bool bShowBorder = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Style")
FLinearColor BorderColour = FLinearColor(0.f, 0.f, 0.f, 0.8f);
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Style",
meta = (ClampMin = "0", ClampMax = "10"))
float BorderWidth = 1.f;
// ---- Toggles de efeito ----
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Effects")
bool bShowTrackGrid = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Effects")
bool bShowEdge = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar|Effects")
bool bShowShimmer = false;
};
/**
* ProgressBar — padrao multi-map Hyper-style. Variantes (HP/MP/XP/Cast/...) sao
* editadas direto no DT_UI_Styles; cada UUIProgressBar_Base referencia uma key
* FName (dropdown via meta=GetOptions resolve esse mapa em runtime+editor).
*/
USTRUCT(BlueprintType)
struct ZMMO_API FUIStyleProgressBar
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar")
FLinearColor TrackColor = FLinearColor(FColor(14, 20, 36)); // Panel3
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar")
FLinearColor BorderColor = FLinearColor(FColor(58, 75, 120, 140));
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar")
float Height = 10.f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar")
float CornerRadius = 6.f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar")
float BorderWidth = 1.f;
/** Cor de preenchimento por tipo (Health/Mana/XP...). */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|ProgressBar")
TMap<EUIProgressBarType, FLinearColor> FillByType;
TMap<FName, FUIStyleProgressBarVariant> Variants;
};
USTRUCT(BlueprintType)

View File

@@ -81,6 +81,16 @@ enum class EUIProgressBarType : uint8
Generic UMETA(DisplayName = "Generic")
};
/** Preset que controla Brush.DrawAs em todos os UImages da ProgressBar. */
UENUM(BlueprintType)
enum class EUIProgressBarStyle : uint8
{
/** DrawAs=Image. Sem mascara nos cantos. */
Box UMETA(DisplayName = "Box"),
/** DrawAs=RoundedBox. Cantos arredondados via Slate nativo (pixel-perfect). */
Rounded UMETA(DisplayName = "Rounded"),
};
UENUM(BlueprintType)
enum class EUIHeaderType : uint8
{

View File

@@ -2,10 +2,15 @@
#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 "ZMMOThemeSubsystem.h"
namespace
{
@@ -46,6 +51,50 @@ namespace
{
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 UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
{
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()
@@ -64,9 +113,16 @@ void UUIProgressBar_Base::NativePreConstruct()
SecondaryElapsed = 0.f;
bAnimatingSecondary = false;
ApplyBrushStyle();
EnsureMIDs();
ApplyMaterialOverrides();
if (bUseTheme)
{
RefreshUIStyle();
}
else
{
ApplyBrushStyle();
EnsureMIDs();
ApplyMaterialOverrides();
}
ApplyPrimaryToMID(CurrentPrimaryLevel);
ApplySecondaryToMID(CurrentSecondaryLevel);
}
@@ -75,13 +131,56 @@ void UUIProgressBar_Base::NativeConstruct()
{
Super::NativeConstruct();
ApplyBrushStyle();
EnsureMIDs();
ApplyMaterialOverrides();
if (!bThemeBound)
{
if (const UGameInstance* GI = GetGameInstance())
{
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
{
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 (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
{
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);
@@ -584,3 +683,79 @@ void UUIProgressBar_Base::ApplySecondaryToMID(float Value)
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();
}

View File

@@ -2,20 +2,12 @@
#include "CoreMinimal.h"
#include "CommonUserWidget.h"
#include "UI/UIStyleTypes.h"
#include "UIProgressBar_Base.generated.h"
class UImage;
class UMaterialInstanceDynamic;
/** Preset que controla Brush.DrawAs (Image=Box, RoundedBox=Rounded) em ambos os widgets. */
UENUM(BlueprintType)
enum class EUIProgressBarStyle : uint8
{
/** DrawAs=Image. Sem mascara nos cantos. */
Box UMETA(DisplayName = "Box"),
/** DrawAs=RoundedBox. Cantos arredondados via Slate nativo (pixel-perfect). */
Rounded UMETA(DisplayName = "Rounded"),
};
struct FUIStyleProgressBarVariant;
/**
* ProgressBar do ZMMO. Wrappa um UImage (FillImage) + UImage de background
@@ -33,6 +25,35 @@ class ZMMO_API UUIProgressBar_Base : public UCommonUserWidget
GENERATED_BODY()
public:
// === Theme (DT_UI_Styles integration) ===
/**
* true = le toda a config visual (materiais + style + toggles) do
* DT_UI_Styles (FUIStyleProgressBar.Variants[Variant]). Tema
* centralizado, ignora as UPROPERTYs override individuais abaixo.
* false = ignora a DT, usa apenas as UPROPERTYs/toggles do widget.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Theme")
bool bUseTheme = false;
/**
* Chave da variante (HP/MP/XP/Cast/...). Dropdown popula via
* meta=GetOptions lendo DT_UI_Styles.Default.ProgressBar.Variants. Vazio
* = sem theme aplicado (igual bUseTheme=false).
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Theme",
meta = (EditCondition = "bUseTheme", EditConditionHides,
GetOptions = "GetProgressBarVariantOptions"))
FName Variant;
/** Re-resolve a variante atual e reaplica nos widgets. */
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Theme")
void RefreshUIStyle();
/** Populador do dropdown (meta=GetOptions) das variantes. */
UFUNCTION()
TArray<FString> GetProgressBarVariantOptions() const;
// === Levels ===
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar",
@@ -384,6 +405,7 @@ public:
protected:
virtual void NativePreConstruct() override;
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
UPROPERTY(meta = (BindWidget))
@@ -423,6 +445,12 @@ private:
void ApplyMaterialOverrides();
void ApplyBrushStyle();
void UpdateEdgeVisibility();
void ApplyThemeVariant(const FUIStyleProgressBarVariant& Variant);
UFUNCTION()
void HandleThemeChanged(FName NewThemeId);
bool bThemeBound = false;
float CurrentPrimaryLevel = 1.f;
float TargetPrimaryLevel = 1.f;