Compare commits
2 Commits
7fa10b4cb9
...
5d44647170
| Author | SHA1 | Date | |
|---|---|---|---|
| 5d44647170 | |||
| 1794e5d418 |
@@ -86,6 +86,15 @@ GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient
|
|||||||
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="ZMMOPlayerCharacter")
|
+ActiveClassRedirects=(OldClassName="TP_ThirdPersonCharacter",NewClassName="ZMMOPlayerCharacter")
|
||||||
+ActiveClassRedirects=(OldClassName="ZMMOCharacter",NewClassName="ZMMOPlayerCharacter")
|
+ActiveClassRedirects=(OldClassName="ZMMOCharacter",NewClassName="ZMMOPlayerCharacter")
|
||||||
|
|
||||||
|
[CoreRedirects]
|
||||||
|
; Migração v1→v2 do FUIStylePanel: TMap<EUIPanelTexture,...> (Enum) → TMap<FName,...>.
|
||||||
|
; Os campos *_DEPRECATED preservam a leitura do asset antigo; PostSerialize copia
|
||||||
|
; pros novos ByName e após re-save os legacy ficam vazios. Os redirects podem
|
||||||
|
; ser removidos quando todos os DTs do projeto tiverem sido re-salvos.
|
||||||
|
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelBackground",NewName="/Script/ZMMO.UIStylePanel.PanelBackground_DEPRECATED")
|
||||||
|
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelOutline",NewName="/Script/ZMMO.UIStylePanel.PanelOutline_DEPRECATED")
|
||||||
|
+PropertyRedirects=(OldName="/Script/ZMMO.UIStylePanel.PanelOutlineEffect",NewName="/Script/ZMMO.UIStylePanel.PanelOutlineEffect_DEPRECATED")
|
||||||
|
|
||||||
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
[/Script/AndroidFileServerEditor.AndroidFileServerRuntimeSettings]
|
||||||
bEnablePlugin=True
|
bEnablePlugin=True
|
||||||
bAllowNetworkConnection=True
|
bAllowNetworkConnection=True
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/ZMMO/UI/Shared/UI_ProgressBar_Master.uasset
Normal file
BIN
Content/ZMMO/UI/Shared/UI_ProgressBar_Master.uasset
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
48
Source/ZMMO/Data/UI/UIStyleTokens.cpp
Normal file
48
Source/ZMMO/Data/UI/UIStyleTokens.cpp
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
#include "UIStyleTokens.h"
|
||||||
|
|
||||||
|
#include "UObject/Class.h"
|
||||||
|
#include "UObject/UnrealType.h"
|
||||||
|
|
||||||
|
void FUIStylePanel::PostSerialize(const FArchive& Ar)
|
||||||
|
{
|
||||||
|
// Migração v1→v2: TMap<EUIPanelTexture, ...> (legacy) → TMap<FName, ...> (atual).
|
||||||
|
// Roda no PostLoad de cada FUIStyleRow; depois do primeiro re-save no editor
|
||||||
|
// os campos *_DEPRECATED ficam vazios e este código vira no-op.
|
||||||
|
if (!Ar.IsLoading())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UEnum* EnumPtr = StaticEnum<EUIPanelTexture>();
|
||||||
|
if (EnumPtr == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto MigrateOne = [EnumPtr](
|
||||||
|
TMap<EUIPanelTexture, FSlateBrush>& Legacy,
|
||||||
|
TMap<FName, FSlateBrush>& ByName)
|
||||||
|
{
|
||||||
|
if (Legacy.IsEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const TPair<EUIPanelTexture, FSlateBrush>& Pair : Legacy)
|
||||||
|
{
|
||||||
|
if (Pair.Key == EUIPanelTexture::None)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const FName KeyName(*EnumPtr->GetAuthoredNameStringByValue(static_cast<int64>(Pair.Key)));
|
||||||
|
if (!ByName.Contains(KeyName))
|
||||||
|
{
|
||||||
|
ByName.Add(KeyName, Pair.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Legacy.Reset();
|
||||||
|
};
|
||||||
|
|
||||||
|
MigrateOne(PanelBackground_DEPRECATED, PanelBackgroundByName);
|
||||||
|
MigrateOne(PanelOutline_DEPRECATED, PanelOutlineByName);
|
||||||
|
MigrateOne(PanelOutlineEffect_DEPRECATED, PanelOutlineEffectByName);
|
||||||
|
}
|
||||||
@@ -290,23 +290,58 @@ struct ZMMO_API FUIPanelBrushSet
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Espelha 1:1 o Struct_UI_Style_Panels do Hyper, agora com 3 brushes por
|
* Espelha 1:1 o Struct_UI_Style_Panels do Hyper. 3 brushes por categoria
|
||||||
* EUIPanelTexture: fundo, contorno e efeito sobre o contorno. Tudo
|
* (FName livre): fundo, contorno e efeito sobre o contorno. Categorias são
|
||||||
* data-driven via brush no DT_UI_Styles.
|
* editadas direto no DT_UI_Styles — UUIPanel_Base resolve via dropdown
|
||||||
|
* dinâmico (meta=GetOptions).
|
||||||
|
*
|
||||||
|
* Migração: assets v1 tinham TMap<EUIPanelTexture, ...>; os campos
|
||||||
|
* *_DEPRECATED preservam essas keys via PropertyRedirect no DefaultEngine.ini.
|
||||||
|
* PostSerialize copia legacy→ByName no PostLoad — após re-save no editor,
|
||||||
|
* o legacy fica vazio e o asset só carrega o ByName.
|
||||||
*/
|
*/
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
struct ZMMO_API FUIStylePanel
|
struct ZMMO_API FUIStylePanel
|
||||||
{
|
{
|
||||||
GENERATED_BODY()
|
GENERATED_BODY()
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture")
|
// ---- Novo (FName livre) -------------------------------------------
|
||||||
TMap<EUIPanelTexture, FSlateBrush> PanelBackground;
|
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture")
|
||||||
TMap<EUIPanelTexture, FSlateBrush> PanelOutline;
|
TMap<FName, FSlateBrush> PanelBackgroundByName;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture")
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture")
|
||||||
TMap<EUIPanelTexture, FSlateBrush> PanelOutlineEffect;
|
TMap<FName, FSlateBrush> PanelOutlineByName;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture")
|
||||||
|
TMap<FName, FSlateBrush> PanelOutlineEffectByName;
|
||||||
|
|
||||||
|
// ---- Legacy (carrega assets antigos via CoreRedirect) -------------
|
||||||
|
//
|
||||||
|
// Não aparecem no Details (DeprecatedProperty); persistem só pra leitura
|
||||||
|
// do asset pré-migração. PostSerialize copia o conteúdo pros campos
|
||||||
|
// ByName e zera os legacy.
|
||||||
|
|
||||||
|
UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Use PanelBackgroundByName (FName)."))
|
||||||
|
TMap<EUIPanelTexture, FSlateBrush> PanelBackground_DEPRECATED;
|
||||||
|
|
||||||
|
UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Use PanelOutlineByName (FName)."))
|
||||||
|
TMap<EUIPanelTexture, FSlateBrush> PanelOutline_DEPRECATED;
|
||||||
|
|
||||||
|
UPROPERTY(meta = (DeprecatedProperty, DeprecationMessage = "Use PanelOutlineEffectByName (FName)."))
|
||||||
|
TMap<EUIPanelTexture, FSlateBrush> PanelOutlineEffect_DEPRECATED;
|
||||||
|
|
||||||
|
/** Chamado automaticamente após Serialize. Migra dados legacy→ByName. */
|
||||||
|
void PostSerialize(const FArchive& Ar);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct TStructOpsTypeTraits<FUIStylePanel> : public TStructOpsTypeTraitsBase2<FUIStylePanel>
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
WithPostSerialize = true,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
USTRUCT(BlueprintType)
|
USTRUCT(BlueprintType)
|
||||||
|
|||||||
@@ -62,21 +62,21 @@ void UUIPanel_Base::RefreshUIStyle()
|
|||||||
return B;
|
return B;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
auto ResolveFromTheme = [](EUIPanelTexture Key,
|
auto ResolveFromTheme = [](FName Key,
|
||||||
const TMap<EUIPanelTexture, FSlateBrush>& Map) -> const FSlateBrush*
|
const TMap<FName, FSlateBrush>& Map) -> const FSlateBrush*
|
||||||
{
|
{
|
||||||
return (Key == EUIPanelTexture::None) ? nullptr : Map.Find(Key);
|
return Key.IsNone() ? nullptr : Map.Find(Key);
|
||||||
};
|
};
|
||||||
|
|
||||||
const FSlateBrush* BgTex = bUseTheme
|
const FSlateBrush* BgTex = bUseTheme
|
||||||
? ResolveFromTheme(BackgroundKey, P.PanelBackground)
|
? ResolveFromTheme(BackgroundKey, P.PanelBackgroundByName)
|
||||||
: &Panels.PanelBackground;
|
: &Panels.PanelBackground;
|
||||||
Background->SetBrush(BgTex ? *BgTex : NoDrawBrush);
|
Background->SetBrush(BgTex ? *BgTex : NoDrawBrush);
|
||||||
|
|
||||||
if (Outline)
|
if (Outline)
|
||||||
{
|
{
|
||||||
const FSlateBrush* OlTex = bUseTheme
|
const FSlateBrush* OlTex = bUseTheme
|
||||||
? ResolveFromTheme(OutlineKey, P.PanelOutline)
|
? ResolveFromTheme(OutlineKey, P.PanelOutlineByName)
|
||||||
: &Panels.PanelOutline;
|
: &Panels.PanelOutline;
|
||||||
Outline->SetBrush(OlTex ? *OlTex : NoDrawBrush);
|
Outline->SetBrush(OlTex ? *OlTex : NoDrawBrush);
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ void UUIPanel_Base::RefreshUIStyle()
|
|||||||
if (OutlineEffect)
|
if (OutlineEffect)
|
||||||
{
|
{
|
||||||
const FSlateBrush* OeTex = bUseTheme
|
const FSlateBrush* OeTex = bUseTheme
|
||||||
? ResolveFromTheme(OutlineEffectKey, P.PanelOutlineEffect)
|
? ResolveFromTheme(OutlineEffectKey, P.PanelOutlineEffectByName)
|
||||||
: &Panels.PanelOutlineEffect;
|
: &Panels.PanelOutlineEffect;
|
||||||
OutlineEffect->SetBrush(OeTex ? *OeTex : NoDrawBrush);
|
OutlineEffect->SetBrush(OeTex ? *OeTex : NoDrawBrush);
|
||||||
}
|
}
|
||||||
@@ -136,3 +136,59 @@ void UUIPanel_Base::HandleThemeChanged(FName /*NewThemeId*/)
|
|||||||
{
|
{
|
||||||
RefreshUIStyle();
|
RefreshUIStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
enum class EPanelBrushSlot : uint8 { Background, Outline, OutlineEffect };
|
||||||
|
|
||||||
|
TArray<FString> CollectPanelOptions(EPanelBrushSlot Slot)
|
||||||
|
{
|
||||||
|
TArray<FString> Options;
|
||||||
|
Options.Add(FString()); // entry vazia = "sem brush" (NoDrawType)
|
||||||
|
|
||||||
|
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("UIPanelGetOptions"), false);
|
||||||
|
if (!Row)
|
||||||
|
{
|
||||||
|
return Options;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TMap<FName, FSlateBrush>* Map = nullptr;
|
||||||
|
switch (Slot)
|
||||||
|
{
|
||||||
|
case EPanelBrushSlot::Background: Map = &Row->Style.Panel.PanelBackgroundByName; break;
|
||||||
|
case EPanelBrushSlot::Outline: Map = &Row->Style.Panel.PanelOutlineByName; break;
|
||||||
|
case EPanelBrushSlot::OutlineEffect: Map = &Row->Style.Panel.PanelOutlineEffectByName; break;
|
||||||
|
}
|
||||||
|
if (Map)
|
||||||
|
{
|
||||||
|
for (const TPair<FName, FSlateBrush>& Pair : *Map)
|
||||||
|
{
|
||||||
|
Options.Add(Pair.Key.ToString());
|
||||||
|
}
|
||||||
|
Options.Sort();
|
||||||
|
}
|
||||||
|
return Options;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<FString> UUIPanel_Base::GetPanelBackgroundOptions() const
|
||||||
|
{
|
||||||
|
return CollectPanelOptions(EPanelBrushSlot::Background);
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<FString> UUIPanel_Base::GetPanelOutlineOptions() const
|
||||||
|
{
|
||||||
|
return CollectPanelOptions(EPanelBrushSlot::Outline);
|
||||||
|
}
|
||||||
|
|
||||||
|
TArray<FString> UUIPanel_Base::GetPanelOutlineEffectOptions() const
|
||||||
|
{
|
||||||
|
return CollectPanelOptions(EPanelBrushSlot::OutlineEffect);
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,19 +30,26 @@ public:
|
|||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel")
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel")
|
||||||
bool bUseTheme = true;
|
bool bUseTheme = true;
|
||||||
|
|
||||||
// ---- Modo TEMA: escolhe a chave do mapa FUIStylePanel pra cada Border. ----
|
// ---- Modo TEMA: chave FName do TMap FUIStylePanel pra cada Border. ----
|
||||||
|
//
|
||||||
|
// GetOptions popula dropdown lendo DT_UI_Styles row "Default" — adicione
|
||||||
|
// uma entry em FUIStylePanel.PanelBackgroundByName no DT e a categoria
|
||||||
|
// aparece aqui sem recompilar C++. Vazio = sem brush (NoDrawType).
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel",
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel",
|
||||||
meta = (EditCondition = "bUseTheme", EditConditionHides))
|
meta = (EditCondition = "bUseTheme", EditConditionHides,
|
||||||
EUIPanelTexture BackgroundKey = EUIPanelTexture::None;
|
GetOptions = "GetPanelBackgroundOptions"))
|
||||||
|
FName BackgroundKey;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel",
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel",
|
||||||
meta = (EditCondition = "bUseTheme", EditConditionHides))
|
meta = (EditCondition = "bUseTheme", EditConditionHides,
|
||||||
EUIPanelTexture OutlineKey = EUIPanelTexture::None;
|
GetOptions = "GetPanelOutlineOptions"))
|
||||||
|
FName OutlineKey;
|
||||||
|
|
||||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel",
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel",
|
||||||
meta = (EditCondition = "bUseTheme", EditConditionHides))
|
meta = (EditCondition = "bUseTheme", EditConditionHides,
|
||||||
EUIPanelTexture OutlineEffectKey = EUIPanelTexture::None;
|
GetOptions = "GetPanelOutlineEffectOptions"))
|
||||||
|
FName OutlineEffectKey;
|
||||||
|
|
||||||
// ---- Modo MANUAL: 3 brushes editáveis direto no Details. ----
|
// ---- Modo MANUAL: 3 brushes editáveis direto no Details. ----
|
||||||
|
|
||||||
@@ -54,6 +61,22 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, Category = "UI Style")
|
UFUNCTION(BlueprintCallable, Category = "UI Style")
|
||||||
void RefreshUIStyle();
|
void RefreshUIStyle();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populadores do dropdown (meta=GetOptions) das chaves de textura.
|
||||||
|
* Lêem DT_UI_Styles row "Default" e retornam as FName de cada sub-mapa
|
||||||
|
* do FUIStylePanel. Editar o DT no editor reflete aqui sem recompilar.
|
||||||
|
* São métodos de instância porque o UE precisa de UFUNCTION reflexável;
|
||||||
|
* o conteúdo não usa estado da instância (poderia ser estático).
|
||||||
|
*/
|
||||||
|
UFUNCTION()
|
||||||
|
TArray<FString> GetPanelBackgroundOptions() const;
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
TArray<FString> GetPanelOutlineOptions() const;
|
||||||
|
|
||||||
|
UFUNCTION()
|
||||||
|
TArray<FString> GetPanelOutlineEffectOptions() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void NativePreConstruct() override;
|
virtual void NativePreConstruct() override;
|
||||||
virtual void NativeConstruct() override;
|
virtual void NativeConstruct() override;
|
||||||
|
|||||||
278
Source/ZMMO/Game/UI/Widgets/UIProgressBar_Base.cpp
Normal file
278
Source/ZMMO/Game/UI/Widgets/UIProgressBar_Base.cpp
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
#include "UIProgressBar_Base.h"
|
||||||
|
|
||||||
|
#include "Components/Image.h"
|
||||||
|
#include "Materials/MaterialInstanceDynamic.h"
|
||||||
|
#include "Materials/MaterialInterface.h"
|
||||||
|
#include "Styling/SlateBrush.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr float MinAnimSeconds = 0.001f;
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
FORCEINLINE float EaseOutCubic(float Alpha)
|
||||||
|
{
|
||||||
|
return 1.f - FMath::Pow(1.f - Alpha, 3.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
EnsureMID();
|
||||||
|
ApplyOverridesToMID();
|
||||||
|
ApplyPrimaryToMID(CurrentPrimaryLevel);
|
||||||
|
ApplySecondaryToMID(CurrentSecondaryLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UUIProgressBar_Base::NativeConstruct()
|
||||||
|
{
|
||||||
|
Super::NativeConstruct();
|
||||||
|
|
||||||
|
EnsureMID();
|
||||||
|
ApplyOverridesToMID();
|
||||||
|
ApplyPrimaryToMID(CurrentPrimaryLevel);
|
||||||
|
ApplySecondaryToMID(CurrentSecondaryLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
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::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::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::ApplyOverridesToMID()
|
||||||
|
{
|
||||||
|
if (!FillMID)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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::EnsureMID()
|
||||||
|
{
|
||||||
|
if (FillMID || !FillImage)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UMaterialInterface* Mat = Cast<UMaterialInterface>(FillImage->GetBrush().GetResourceObject());
|
||||||
|
if (!Mat)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FillMID = UMaterialInstanceDynamic::Create(Mat, this);
|
||||||
|
FillImage->SetBrushFromMaterial(FillMID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UUIProgressBar_Base::ApplyPrimaryToMID(float Value)
|
||||||
|
{
|
||||||
|
if (FillMID)
|
||||||
|
{
|
||||||
|
FillMID->SetScalarParameterValue(P_PrimaryLevel, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UUIProgressBar_Base::ApplySecondaryToMID(float Value)
|
||||||
|
{
|
||||||
|
if (FillMID)
|
||||||
|
{
|
||||||
|
FillMID->SetScalarParameterValue(P_SecondaryLevel, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
196
Source/ZMMO/Game/UI/Widgets/UIProgressBar_Base.h
Normal file
196
Source/ZMMO/Game/UI/Widgets/UIProgressBar_Base.h
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CoreMinimal.h"
|
||||||
|
#include "CommonUserWidget.h"
|
||||||
|
#include "UIProgressBar_Base.generated.h"
|
||||||
|
|
||||||
|
class UImage;
|
||||||
|
class UMaterialInstanceDynamic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProgressBar do ZMMO. Wrappa um UImage com material custom
|
||||||
|
* (UI_M_ProgressBar) e expõe API com dois níveis:
|
||||||
|
* Primary (preenchimento atual) + Secondary (preview / damage lag / buffer).
|
||||||
|
*
|
||||||
|
* Modelo assimétrico: SecondaryLevel só aparece visualmente se for MAIOR
|
||||||
|
* que PrimaryLevel — representa heal preview, damage trail, buffer
|
||||||
|
* empilhado em cima da barra principal.
|
||||||
|
*
|
||||||
|
* Cores: por padrão vêm da Material Instance atribuída ao FillImage.
|
||||||
|
* Cada cor tem um toggle de override (InlineEditConditionToggle) que,
|
||||||
|
* quando ligado, sobrescreve o valor da MI via MID em PreConstruct.
|
||||||
|
*/
|
||||||
|
UCLASS(Abstract, Blueprintable)
|
||||||
|
class ZMMO_API UUIProgressBar_Base : public UCommonUserWidget
|
||||||
|
{
|
||||||
|
GENERATED_BODY()
|
||||||
|
|
||||||
|
public:
|
||||||
|
// === Levels ===
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar",
|
||||||
|
meta = (ClampMin = "0", ClampMax = "1"))
|
||||||
|
float InitialPrimaryLevel = 1.f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar",
|
||||||
|
meta = (ClampMin = "0", ClampMax = "1"))
|
||||||
|
float InitialSecondaryLevel = 0.f;
|
||||||
|
|
||||||
|
// === Animation ===
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Animation",
|
||||||
|
meta = (ClampMin = "0", ClampMax = "5"))
|
||||||
|
float PrimaryAnimationSeconds = 0.25f;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Animation",
|
||||||
|
meta = (ClampMin = "0", ClampMax = "5"))
|
||||||
|
float SecondaryAnimationSeconds = 0.8f;
|
||||||
|
|
||||||
|
// === Color overrides (sobrescrevem a MI) ===
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverridePrimaryColour = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (EditCondition = "bOverridePrimaryColour"))
|
||||||
|
FLinearColor PrimaryColour = FLinearColor(0.957f, 0.769f, 0.353f, 1.f);
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverridePrimaryColourBottom = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (EditCondition = "bOverridePrimaryColourBottom"))
|
||||||
|
FLinearColor PrimaryColourBottom = FLinearColor(0.478f, 0.282f, 0.094f, 1.f);
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverrideSecondaryColour = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (EditCondition = "bOverrideSecondaryColour"))
|
||||||
|
FLinearColor SecondaryColour = FLinearColor(0.246201f, 0.002428f, 0.002125f, 1.f);
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverrideSecondaryColourBottom = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (EditCondition = "bOverrideSecondaryColourBottom"))
|
||||||
|
FLinearColor SecondaryColourBottom = FLinearColor(0.123f, 0.001f, 0.001f, 1.f);
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverrideEmptyColour = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Colors",
|
||||||
|
meta = (EditCondition = "bOverrideEmptyColour"))
|
||||||
|
FLinearColor EmptyColour = FLinearColor(0.f, 0.f, 0.f, 0.6f);
|
||||||
|
|
||||||
|
// === Gradient overrides ===
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Gradient",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverrideEnableGradient = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Gradient",
|
||||||
|
meta = (EditCondition = "bOverrideEnableGradient"))
|
||||||
|
bool bEnableGradient = true;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Gradient",
|
||||||
|
meta = (InlineEditConditionToggle))
|
||||||
|
bool bOverrideGradientSplit = false;
|
||||||
|
|
||||||
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ProgressBar|Gradient",
|
||||||
|
meta = (EditCondition = "bOverrideGradientSplit", ClampMin = "0", ClampMax = "1"))
|
||||||
|
float GradientSplit = 0.5f;
|
||||||
|
|
||||||
|
// === Primary API ===
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar")
|
||||||
|
void SetTargetPrimaryLevel(float Primary01);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar")
|
||||||
|
void SetPrimaryLevelImmediate(float Primary01);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintPure, Category = "ProgressBar")
|
||||||
|
float GetCurrentPrimaryLevel() const { return CurrentPrimaryLevel; }
|
||||||
|
|
||||||
|
// === Secondary API ===
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar")
|
||||||
|
void SetTargetSecondaryLevel(float Sec01);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar")
|
||||||
|
void SetSecondaryLevelImmediate(float Sec01);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintPure, Category = "ProgressBar")
|
||||||
|
float GetCurrentSecondaryLevel() const { return CurrentSecondaryLevel; }
|
||||||
|
|
||||||
|
// === Runtime color/gradient setters (também marcam o override pra evitar reset no próximo PreConstruct) ===
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Colors")
|
||||||
|
void SetPrimaryColour(FLinearColor Color);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Colors")
|
||||||
|
void SetPrimaryColourBottom(FLinearColor Color);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Colors")
|
||||||
|
void SetSecondaryColour(FLinearColor Color);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Colors")
|
||||||
|
void SetSecondaryColourBottom(FLinearColor Color);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Colors")
|
||||||
|
void SetEmptyColour(FLinearColor Color);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Gradient")
|
||||||
|
void SetGradientEnabled(bool bEnabled);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Gradient")
|
||||||
|
void SetGradientSplit(float Split01);
|
||||||
|
|
||||||
|
// === Wrappers semânticos ===
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Effects")
|
||||||
|
void ShowHealPreview(float TargetPct, FLinearColor PreviewColor);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Effects")
|
||||||
|
void ShowDamageLag(float OldPct, float NewPct, FLinearColor LagColor);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Effects")
|
||||||
|
void ShowBuffer(float BufferPct, FLinearColor BufferColor);
|
||||||
|
|
||||||
|
UFUNCTION(BlueprintCallable, Category = "ProgressBar|Effects")
|
||||||
|
void ClearSecondary();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void NativePreConstruct() override;
|
||||||
|
virtual void NativeConstruct() override;
|
||||||
|
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
||||||
|
|
||||||
|
UPROPERTY(meta = (BindWidget))
|
||||||
|
TObjectPtr<UImage> FillImage;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UPROPERTY(Transient)
|
||||||
|
TObjectPtr<UMaterialInstanceDynamic> FillMID;
|
||||||
|
|
||||||
|
void EnsureMID();
|
||||||
|
void ApplyPrimaryToMID(float Value);
|
||||||
|
void ApplySecondaryToMID(float Value);
|
||||||
|
void ApplyOverridesToMID();
|
||||||
|
|
||||||
|
float CurrentPrimaryLevel = 1.f;
|
||||||
|
float TargetPrimaryLevel = 1.f;
|
||||||
|
float PrimaryStart = 1.f;
|
||||||
|
float PrimaryElapsed = 0.f;
|
||||||
|
bool bAnimatingPrimary = false;
|
||||||
|
|
||||||
|
float CurrentSecondaryLevel = 0.f;
|
||||||
|
float TargetSecondaryLevel = 0.f;
|
||||||
|
float SecondaryStart = 0.f;
|
||||||
|
float SecondaryElapsed = 0.f;
|
||||||
|
bool bAnimatingSecondary = false;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user