2 Commits

Author SHA1 Message Date
e1fca1ae8d feat(ui/hud): painel de vitais (Nome/Job/Level + HP/SP/EXP) substituindo HpSpBar
UZMMOHudPlayerVitalsWidget (novo): sub-widget do HUD com 4 UUIProgressBar_Base
(HP/SP/BASE EXP/JOB EXP) + nome/classe/level. ApplySnapshot anima HP/SP via
SetTargetPrimaryLevel e formata os readouts; ApplyHpSp pro tick rapido.

UZMMOHudWidget propaga o snapshot pro PlayerVitals e resolve identidade: nome
do AZMMOPlayerState.CharName + job via UZMMOJobsLibrary.GetJobDisplayName(ClassId).
HpSpBar legado removido do WBP_HUD.

WBP_PlayerVitalsPanel: layout compacto (520w) com colunas alinhadas (label 28 /
bar FILL / readout 116 right-align) independente do tamanho do numero. Sem portrait.

MIs por barra: UI_M_ProgressBar_SP/BaseEXP/JobEXP/Loading (cores do
hud_layout_modal_New.html).

EXP/JOB readout mostra exp absoluto por ora — barras de EXP aguardam o servidor
enviar exp-to-next no snapshot pra calcular a porcentagem.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 00:34:03 -03:00
c9492a3910 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>
2026-05-28 00:33:43 -03:00
16 changed files with 515 additions and 35 deletions

Binary file not shown.

Binary file not shown.

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

@@ -0,0 +1,96 @@
#include "ZMMOHudPlayerVitalsWidget.h"
#include "Components/TextBlock.h"
#include "UI/Widgets/UIProgressBar_Base.h"
#include "Internationalization/Text.h"
namespace
{
/** Formata int com separador de milhar do locale (ex.: 9840 -> "9,840"). */
FText FormatNumber(int64 Value)
{
return FText::AsNumber(Value);
}
float SafeRatio(int32 Current, int32 Max)
{
return Max > 0 ? FMath::Clamp(static_cast<float>(Current) / static_cast<float>(Max), 0.f, 1.f) : 0.f;
}
}
void UZMMOHudPlayerVitalsWidget::ApplySnapshot(const FZMMOAttributesSnapshot& Snapshot)
{
LastSnapshot = Snapshot;
// HP / SP (pool efetivo — % real)
ApplyHpSp(Snapshot.Hp, Snapshot.MaxHp, Snapshot.Sp, Snapshot.MaxSp);
// Level
if (LvlText)
{
LvlText->SetText(FText::FromString(FString::Printf(TEXT("LVL %d"), Snapshot.BaseLevel)));
}
// BASE / JOB EXP — sem "exp-to-next" no snapshot. Readout mostra valor
// absoluto acumulado; as barras ficam pra quando a curva de exp existir.
if (ExpReadout)
{
ExpReadout->SetText(FormatNumber(Snapshot.BaseExp));
}
if (JobReadout)
{
JobReadout->SetText(FormatNumber(Snapshot.JobExp));
}
OnSnapshotApplied(Snapshot);
}
void UZMMOHudPlayerVitalsWidget::ApplyHpSp(int32 Hp, int32 MaxHp, int32 Sp, int32 MaxSp)
{
LastSnapshot.Hp = Hp;
LastSnapshot.MaxHp = MaxHp;
LastSnapshot.Sp = Sp;
LastSnapshot.MaxSp = MaxSp;
if (HpBar)
{
HpBar->SetTargetPrimaryLevel(SafeRatio(Hp, MaxHp));
}
if (SpBar)
{
SpBar->SetTargetPrimaryLevel(SafeRatio(Sp, MaxSp));
}
if (HpReadout)
{
HpReadout->SetText(FText::Format(
NSLOCTEXT("ZMMOHud", "HpSpReadout", "{0}/{1}"),
FormatNumber(Hp), FormatNumber(MaxHp)));
}
if (SpReadout)
{
SpReadout->SetText(FText::Format(
NSLOCTEXT("ZMMOHud", "HpSpReadout", "{0}/{1}"),
FormatNumber(Sp), FormatNumber(MaxSp)));
}
}
void UZMMOHudPlayerVitalsWidget::SetCharName(const FString& InName)
{
if (NameText)
{
NameText->SetText(FText::FromString(InName));
}
}
void UZMMOHudPlayerVitalsWidget::SetClassName(const FString& InClassName)
{
if (ClassText)
{
ClassText->SetText(FText::FromString(InClassName));
}
}
void UZMMOHudPlayerVitalsWidget::OnSnapshotApplied_Implementation(const FZMMOAttributesSnapshot& /*Snapshot*/)
{
// Default vazio — skin do WBP estende se quiser (low-HP flash, etc.).
}

View File

@@ -0,0 +1,92 @@
#pragma once
#include "CommonUserWidget.h"
#include "CoreMinimal.h"
#include "ZMMOAttributeTypes.h"
#include "ZMMOHudPlayerVitalsWidget.generated.h"
class UUIProgressBar_Base;
class UTextBlock;
/**
* Sub-widget do HUD: painel de vitais do player (portrait + nome/job/level +
* barras HP/SP/BASE EXP/JOB EXP). Sem auto-bind no AttributeComponent — o
* parent (UZMMOHudWidget) propaga snapshots via ApplySnapshot/ApplyHpSp.
*
* Barras são UUIProgressBar_Base (material custom Primary/Secondary). HP/SP
* têm pool efetivo no snapshot → % real. BASE/JOB EXP só têm exp acumulado
* (sem "exp-to-next") — barras de EXP ficam pra quando a curva existir;
* por ora o readout mostra o valor absoluto.
*
* WBP filho (WBP_PlayerVitalsPanel) deve ter widgets com EXATAMENTE estes
* nomes: HpBar, SpBar (obrigatórios); ExpBar, JobBar, NameText, ClassText,
* LvlText, HpReadout, SpReadout, ExpReadout, JobReadout (opcionais).
*/
UCLASS(Abstract, Blueprintable, BlueprintType)
class ZMMO_API UZMMOHudPlayerVitalsWidget : public UCommonUserWidget
{
GENERATED_BODY()
public:
/** Atualiza todos os campos a partir do snapshot. Chamado pelo UZMMOHudWidget. */
UFUNCTION(BlueprintCallable, Category = "Zeus|HUD")
void ApplySnapshot(const FZMMOAttributesSnapshot& Snapshot);
/** Atualiza apenas HP/SP (otimização do tick — sem mexer em level/exp). */
UFUNCTION(BlueprintCallable, Category = "Zeus|HUD")
void ApplyHpSp(int32 Hp, int32 MaxHp, int32 Sp, int32 MaxSp);
/** Nome do char — vem do PlayerState (não está no snapshot). */
UFUNCTION(BlueprintCallable, Category = "Zeus|HUD")
void SetCharName(const FString& InName);
/** Nome do job/classe — vem do JobsDatabase via ClassId (não é string no snapshot). */
UFUNCTION(BlueprintCallable, Category = "Zeus|HUD")
void SetClassName(const FString& InClassName);
protected:
/** Hook BP pra skin reagir (cores low-HP, animações, etc.). */
UFUNCTION(BlueprintNativeEvent, Category = "Zeus|HUD")
void OnSnapshotApplied(const FZMMOAttributesSnapshot& Snapshot);
virtual void OnSnapshotApplied_Implementation(const FZMMOAttributesSnapshot& Snapshot);
// === BindWidget — barras (HP/SP obrigatórias) ===
UPROPERTY(BlueprintReadOnly, meta = (BindWidget), Category = "Zeus|HUD")
TObjectPtr<UUIProgressBar_Base> HpBar;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget), Category = "Zeus|HUD")
TObjectPtr<UUIProgressBar_Base> SpBar;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UUIProgressBar_Base> ExpBar;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UUIProgressBar_Base> JobBar;
// === BindWidget — textos (todos opcionais) ===
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> NameText;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> ClassText;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> LvlText;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> HpReadout;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> SpReadout;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> ExpReadout;
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
TObjectPtr<UTextBlock> JobReadout;
private:
/** Último snapshot recebido (cache pra ApplyHpSp manter MaxHp/MaxSp). */
UPROPERTY(Transient)
FZMMOAttributesSnapshot LastSnapshot;
};

View File

@@ -10,6 +10,9 @@
#include "ZMMO.h"
#include "ZMMOAttributeComponent.h"
#include "ZMMOHudHpSpWidget.h"
#include "ZMMOHudPlayerVitalsWidget.h"
#include "ZMMOJobsLibrary.h"
#include "ZMMOPlayerState.h"
UZMMOHudWidget::UZMMOHudWidget(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
@@ -98,12 +101,28 @@ void UZMMOHudWidget::UnbindFromComponent()
void UZMMOHudWidget::HandleAttributesChanged(const FZMMOAttributesSnapshot& Snapshot)
{
// Propaga snapshot aos sub-widgets que ja existem. Em V1 so' HpSpBar.
// Propaga snapshot aos sub-widgets que ja existem.
if (HpSpBar)
{
HpSpBar->ApplySnapshot(Snapshot);
}
// Futuros: PlayerInfo->ApplySnapshot, Buffs->RefreshIcons, etc.
if (PlayerVitals)
{
PlayerVitals->ApplySnapshot(Snapshot);
// Identidade: nome vem do PlayerState (não está no snapshot); job vem
// do JobsSubsystem resolvendo ClassId -> display name.
if (UZMMOAttributeComponent* Comp = BoundComponent.Get())
{
if (const AZMMOPlayerState* PS = Cast<AZMMOPlayerState>(Comp->GetOwner()))
{
PlayerVitals->SetCharName(PS->CharName);
}
}
PlayerVitals->SetClassName(
UZMMOJobsLibrary::GetJobDisplayName(this, Snapshot.ClassId).ToString());
}
// Futuros: Buffs->RefreshIcons, etc.
}
void UZMMOHudWidget::HandleHpSpChanged(int32 Hp, int32 Sp)
@@ -115,6 +134,10 @@ void UZMMOHudWidget::HandleHpSpChanged(int32 Hp, int32 Sp)
{
HpSpBar->ApplyHpSp(Hp, Snap.MaxHp, Sp, Snap.MaxSp);
}
if (PlayerVitals)
{
PlayerVitals->ApplyHpSp(Hp, Snap.MaxHp, Sp, Snap.MaxSp);
}
}
}

View File

@@ -10,6 +10,7 @@ class UTextBlock;
class UWidget;
class UZMMOAttributeComponent;
class UZMMOHudHpSpWidget;
class UZMMOHudPlayerVitalsWidget;
/**
* Root da HUD de gameplay. UCommonActivatableWidget pushed pelo
@@ -74,6 +75,12 @@ protected:
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
UZMMOHudHpSpWidget* HpSpBar = nullptr;
/// Painel de vitais novo (portrait + nome/job/level + HP/SP/EXP/JOB bars).
/// Substitui o HpSpBar legado. BindWidgetOptional — coexiste durante a
/// migração; o WBP_HUD pode ter um ou outro.
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional), Category = "Zeus|HUD")
UZMMOHudPlayerVitalsWidget* PlayerVitals = nullptr;
/// Container do toast "LEVEL UP!" (Fase 3). Hidden por default; em
/// `HandleLevelUp` vira visivel por `LevelUpToastDurationSec` segundos
/// (ver `Show/HideLevelUpToast`). WBP_HUD coloca um Border + Image + TextBlock

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;