Files
ZMMO/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h
Mateus Rodrigues e771aec259 wip: UI Button Base + content/config in-progress
Snapshot do trabalho em andamento na branch feat/ui-system: refinamentos do
UIButton_Base (header+impl), atualizacao de styles/themes do botao, mapa de
teste L_ZeusIATest, e demais .uasset/Config tocados durante a sessao de
playtest do meshing. Commit conjunto a pedido do usuario pra deixar a branch
limpa antes do proximo batch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 12:56:28 -03:00

282 lines
12 KiB
C++

#pragma once
#include "CoreMinimal.h"
#include "CommonButtonBase.h"
#include "UIButton_Base.generated.h"
class UImage;
class UCommonTextBlock;
class UMaterialInterface;
class UMaterialInstanceDynamic;
struct FUIStyle;
struct FUIStyleButton;
/** Tipo de borda do botão (fixo por instância; a COR acende por estado). */
UENUM(BlueprintType)
enum class EUIButtonBorderStyle : uint8
{
None UMETA(DisplayName = "Sem borda"),
Simple UMETA(DisplayName = "Linha simples (Slate)"),
Frame UMETA(DisplayName = "Frame (material)")
};
/**
* Snapshot visual de UM estado do botão (Default / Hover / Pressed / Disabled).
* As cores de gradient/glow vão pro material (UI_M_Button via MID); a borda usa
* o RoundedBox nativo do Slate (OutlineSettings) e o scale/opacity são
* RenderTransform do widget. Transições entre estados interpolam esta struct
* inteira (ver UUIButton_Base::NativeTick).
*/
USTRUCT(BlueprintType)
struct ZMMO_API FUIButtonStateVisual
{
GENERATED_BODY()
/** Topo do gradient vertical do fundo (param TopColour do material). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State")
FLinearColor TopColour = FLinearColor(0.910f, 0.753f, 0.376f, 0.18f);
/** Base do gradient vertical (param BottomColour). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State")
FLinearColor BottomColour = FLinearColor(0.659f, 0.471f, 0.188f, 0.10f);
/** Cor do halo externo (camada GlowFx, material UI_M_Button_Glow). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State")
FLinearColor GlowColour = FLinearColor(0.910f, 0.753f, 0.376f, 1.f);
/** Intensidade do halo externo (GlowFx). 0 = sem glow; hover acende (sai pra fora). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State",
meta = (ClampMin = "0", ClampMax = "1"))
float GlowIntensity = 0.f;
/** Cor da borda/cantos (Slate outline no modo Simple, ou material no modo Corners). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State")
FLinearColor BorderColour = FLinearColor(0.831f, 0.659f, 0.314f, 0.28f);
/** Espessura da borda em pixels (Slate OutlineSettings.Width). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State",
meta = (ClampMin = "0", ClampMax = "6"))
float BorderWidth = 1.f;
/** Cor do texto (ButtonText->SetColorAndOpacity). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State")
FLinearColor TextColour = FLinearColor(1.f, 0.847f, 0.533f, 1.f);
/** Scale do botão (CSS transform: scale). 1 = normal, 1.02 = hover, 0.98 = pressed. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State",
meta = (ClampMin = "0.5", ClampMax = "1.5"))
float Scale = 1.f;
/** Opacidade geral do botão (CSS opacity — disabled usa 0.6). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button|State",
meta = (ClampMin = "0", ClampMax = "1"))
float RenderOpacity = 1.f;
};
/**
* Botão base do ZMMO (CommonUI). Mesmo padrão do UUIProgressBar_Base: um UImage
* (`Bg`) com material custom (UI_M_Button) controlado por MID + RoundedBox nativo
* do Slate pra borda/canto. Os estados do UCommonButtonBase (Hover/Pressed/
* Disabled/Selected) trocam o FUIButtonStateVisual alvo; a transição interpola
* suave no Tick (estilo CSS `transition`).
*
* Modo atual = manual (os 4 FUIButtonStateVisual editáveis no Details, já com
* defaults do `btn-primary`). A leitura via DT_UI_Styles (bUseTheme + Variant)
* entra na fase final, reusando esta struct.
*
* WBP filho (UI_Button_Master_New): `Bg` (UImage, obrigatório, material no brush)
* + `ButtonText` (UCommonTextBlock, opcional).
*/
UCLASS(Abstract, Blueprintable)
class ZMMO_API UUIButton_Base : public UCommonButtonBase
{
GENERATED_BODY()
public:
UUIButton_Base(const FObjectInitializer& ObjectInitializer);
/** Define o texto do botão (ButtonText). */
UFUNCTION(BlueprintCallable, Category = "UI Button")
void SetButtonText(const FText& InText);
// === Visual por estado (modo manual; defaults = btn-primary) ===
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
FUIButtonStateVisual DefaultVisual;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
FUIButtonStateVisual HoveredVisual;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
FUIButtonStateVisual PressedVisual;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
FUIButtonStateVisual DisabledVisual;
/** Estado "selecionado" (tabs/toggles). Default = igual ao Hovered. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
FUIButtonStateVisual SelectedVisual;
/** Raio do canto em pixels (Slate RoundedBox). Comum a todos os estados. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual",
meta = (ClampMin = "0", ClampMax = "32"))
float CornerRadius = 2.f;
/** Tipo de borda (independente dos cantos): sem borda, linha Slate ou frame material. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
EUIButtonBorderStyle BorderStyle = EUIButtonBorderStyle::Frame;
/** Liga os cantos (corner brackets) — INDEPENDENTE da borda. Pode ter os dois,
* só um, ou nenhum. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
bool bShowCorners = true;
/** Material do fundo (UI_M_Button). Fallback quando o brush do Bg não traz
* material próprio. Defaults resolvidos no construtor. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Button|Visual")
TObjectPtr<UMaterialInterface> BgMaterial;
/** Material do halo externo (UI_M_Button_Glow), aplicado no GlowFx. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Button|Visual")
TObjectPtr<UMaterialInterface> GlowMaterial;
/** Material dos cantos (UI_M_CornerBrackets), aplicado no Corners. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Button|Visual")
TObjectPtr<UMaterialInterface> CornerMaterial;
/** Material da moldura (UI_M_Button_Frame), aplicado no BorderFx. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Button|Visual")
TObjectPtr<UMaterialInterface> FrameMaterial;
/** Padding do conteúdo (texto) dentro do botão. btn-primary = 28px horiz /
* 12px vert. Aplicado no slot do ButtonText em PreConstruct (o texto fica
* centralizado). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual")
FMargin ContentPadding = FMargin(28.f, 12.f, 28.f, 12.f);
/** Quanto o halo externo (GlowFx) vaza pra fora do botão, em pixels. Aplicado
* como padding negativo no slot do GlowFx em PreConstruct. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual",
meta = (ClampMin = "0", ClampMax = "64"))
float GlowExtent = 16.f;
/** Desloca os cantos. Negativo = pra FORA (abraçando o botão, estilo CSS);
* positivo = pra dentro. Aplicado no slot do Corners em PreConstruct. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual",
meta = (ClampMin = "-32", ClampMax = "32"))
float CornerInset = -5.f;
/** Comprimento de cada braço do "L" (fração da altura). Maior = L mais longo. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual",
meta = (ClampMin = "0.05", ClampMax = "1.0"))
float CornerLength = 0.35f;
/** Espessura/peso do traço dos cantos (fração da altura). Menor = mais fino. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual",
meta = (ClampMin = "0.005", ClampMax = "0.3"))
float CornerThickness = 0.04f;
/** Deslocamento da sombra (GlowFx) pra baixo, em px — dá o look de drop shadow. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Visual",
meta = (ClampMin = "0", ClampMax = "32"))
float GlowOffsetY = 4.f;
/** Duração da transição entre estados (s). 0 = troca instantânea. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Button|Animation",
meta = (ClampMin = "0", ClampMax = "1"))
float TransitionSeconds = 0.12f;
protected:
virtual void NativePreConstruct() override;
virtual void NativeConstruct() override;
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
virtual int32 NativePaint(const FPaintArgs& Args, const FGeometry& AllottedGeometry,
const FSlateRect& MyCullingRect, FSlateWindowElementList& OutDrawElements,
int32 LayerId, const FWidgetStyle& InWidgetStyle, bool bParentEnabled) const override;
// === Hooks de estado do UCommonButtonBase ===
virtual void NativeOnHovered() override;
virtual void NativeOnUnhovered() override;
virtual void NativeOnPressed() override;
virtual void NativeOnReleased() override;
virtual void NativeOnEnabled() override;
virtual void NativeOnDisabled() override;
virtual void NativeOnSelected(bool bBroadcast) override;
virtual void NativeOnDeselected(bool bBroadcast) override;
// === BindWidget (espelham a árvore do UI_Button_Master_New) ===
// Todos BindWidgetOptional pra não quebrar WBPs que herdam UUIButton_Base sem
// essas peças — sem elas o visual degrada (não pinta), mas não quebra.
/** Halo externo (atrás do Bg, com padding negativo pra vazar pra fora). */
UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional))
TObjectPtr<UImage> GlowFx;
/** Fundo (gradient). */
UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional))
TObjectPtr<UImage> Bg;
/** Moldura/frame (material), visível só no BorderStyle = Frame. */
UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional))
TObjectPtr<UImage> BorderFx;
/** Cantos (corner brackets), visível só no BorderStyle = Corners. */
UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional))
TObjectPtr<UImage> Corners;
UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional))
TObjectPtr<UCommonTextBlock> ButtonText;
// === Acesso ao estilo ativo (DT_UI_Styles) — usado na fase final ===
/** Carrega DT_UI_Styles e devolve o FUIStyle da row pedida (default "Default"). */
const FUIStyle* GetActiveUIStyle(FName ThemeId = TEXT("Default")) const;
/** Atalho: devolve só o bloco Button do FUIStyle ativo. */
const FUIStyleButton* GetActiveButtonStyle(FName ThemeId = TEXT("Default")) const;
private:
/** Cria os MIDs a partir do material no brush de cada imagem (idempotente). */
void EnsureMID();
/** Passa a proporção W/H de CADA camada (cantos/frame/glow) pro respectivo
* material que compensa aspect. Chamado no NativePaint — roda no Designer E
* em runtime (o Tick NÃO roda no Designer, por isso o traço esticava lá). */
void ApplyAspectToLayers() const;
/** Recalcula o estado-alvo (disabled>pressed>hovered>selected>default) e transiciona. */
void RefreshState();
/** Inicia transição pro visual alvo (ou aplica direto se TransitionSeconds≈0). */
void GoToState(const FUIButtonStateVisual& Target);
/** Empurra um visual pros widgets (MID + borda Slate + scale/opacity + texto). */
void ApplyVisual(const FUIButtonStateVisual& V);
static FUIButtonStateVisual LerpVisual(const FUIButtonStateVisual& A, const FUIButtonStateVisual& B, float T);
UPROPERTY(Transient)
TObjectPtr<UMaterialInstanceDynamic> BgMID;
UPROPERTY(Transient)
TObjectPtr<UMaterialInstanceDynamic> GlowMID;
UPROPERTY(Transient)
TObjectPtr<UMaterialInstanceDynamic> CornerMID;
UPROPERTY(Transient)
TObjectPtr<UMaterialInstanceDynamic> BorderMID;
bool bHoveredState = false;
bool bPressedState = false;
bool bDisabledState = false;
bool bSelectedState = false;
FUIButtonStateVisual FromVisual;
FUIButtonStateVisual ToVisual;
FUIButtonStateVisual CurrentVisual;
float TransitionElapsed = 0.f;
bool bTransitioning = false;
};