Compare commits
2 Commits
88eb20eefa
...
e1fca1ae8d
| Author | SHA1 | Date | |
|---|---|---|---|
| e1fca1ae8d | |||
| c9492a3910 |
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/UI/HUD/WBP_PlayerVitalsPanel.uasset
Normal file
BIN
Content/ZMMO/UI/HUD/WBP_PlayerVitalsPanel.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
96
Source/ZMMO/Game/UI/InGame/ZMMOHudPlayerVitalsWidget.cpp
Normal file
96
Source/ZMMO/Game/UI/InGame/ZMMOHudPlayerVitalsWidget.cpp
Normal 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.).
|
||||
}
|
||||
92
Source/ZMMO/Game/UI/InGame/ZMMOHudPlayerVitalsWidget.h
Normal file
92
Source/ZMMO/Game/UI/InGame/ZMMOHudPlayerVitalsWidget.h
Normal 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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user