feat(ui): fundacao CommonUI + UUIButton_Base (Abstract)

Habilita CommonUI como base da UI do ZMMO (decisao de arquitetura): modulos CommonUI/CommonInput no Build.cs + include path Game/UI/Widgets; CommonGameViewportClient no DefaultEngine.ini. Adiciona EUIButtonVariant (Primary/Secondary/Danger/Ghost). Cria UUIButton_Base (UCLASS Abstract : UCommonButtonBase): CommonUI cuida de input/foco/click; o C++ resolve os tokens via UZMMOThemeSubsystem::GetActiveUIStyle() e reage a OnThemeChanged; entrega ao WBP por BP_ApplyUIStyle (split contrato C++ / visual Blueprint). CommonInput data/settings deferido p/ a fiacao de input.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-18 21:28:45 -03:00
parent 1c06d69174
commit ab74ef8b17
5 changed files with 163 additions and 0 deletions

View File

@@ -21,6 +21,16 @@ enum class EUITheme : uint8
RPG UMETA(DisplayName = "RPG")
};
/** Variante visual do botão (mapeia 1:1 com os campos de FUIStyleButton). */
UENUM(BlueprintType)
enum class EUIButtonVariant : uint8
{
Primary UMETA(DisplayName = "Primary"),
Secondary UMETA(DisplayName = "Secondary"),
Danger UMETA(DisplayName = "Danger"),
Ghost UMETA(DisplayName = "Ghost")
};
/** Forma/silhueta de um botão — usada pelo widget para escolher dimensões. */
UENUM(BlueprintType)
enum class EUIButtonShape : uint8

View File

@@ -0,0 +1,89 @@
#include "UIButton_Base.h"
#include "ZMMOThemeSubsystem.h"
#include "Engine/GameInstance.h"
namespace
{
/** Resolve o FUIStyle ativo; fallback p/ defaults (preview de designer). */
const FUIStyle& ResolveActiveStyle(const UUserWidget* Widget, const FUIStyle& Fallback)
{
if (Widget)
{
if (const UGameInstance* GI = Widget->GetGameInstance())
{
if (const UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
{
return Theme->GetActiveUIStyle();
}
}
}
return Fallback; // sem GameInstance (design-time): Aurora Arcana default
}
}
const FUIStyleButtonVariant& UUIButton_Base::ResolveVariant(const FUIStyleButton& Button) const
{
switch (Variant)
{
case EUIButtonVariant::Secondary: return Button.Secondary;
case EUIButtonVariant::Danger: return Button.Danger;
case EUIButtonVariant::Ghost: return Button.Ghost;
case EUIButtonVariant::Primary:
default: return Button.Primary;
}
}
void UUIButton_Base::RefreshUIStyle()
{
const FUIStyle Fallback; // defaults do struct = paleta Aurora Arcana
const FUIStyle& ActiveStyle = ResolveActiveStyle(this, Fallback);
BP_ApplyUIStyle(ActiveStyle.Button, ResolveVariant(ActiveStyle.Button));
}
void UUIButton_Base::NativePreConstruct()
{
Super::NativePreConstruct();
RefreshUIStyle(); // preview no designer (usa defaults se não há GameInstance)
}
void UUIButton_Base::NativeConstruct()
{
Super::NativeConstruct();
if (!bThemeBound)
{
if (const UGameInstance* GI = GetGameInstance())
{
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
{
Theme->OnThemeChanged.AddDynamic(this, &UUIButton_Base::HandleThemeChanged);
bThemeBound = true;
}
}
}
RefreshUIStyle();
}
void UUIButton_Base::NativeDestruct()
{
if (bThemeBound)
{
if (const UGameInstance* GI = GetGameInstance())
{
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
{
Theme->OnThemeChanged.RemoveDynamic(this, &UUIButton_Base::HandleThemeChanged);
}
}
bThemeBound = false;
}
Super::NativeDestruct();
}
void UUIButton_Base::HandleThemeChanged(FName /*NewThemeId*/)
{
RefreshUIStyle();
}

View File

@@ -0,0 +1,59 @@
#pragma once
#include "CoreMinimal.h"
#include "CommonButtonBase.h"
#include "UI/UIStyleTypes.h"
#include "UI/UIStyleTokens.h"
#include "UIButton_Base.generated.h"
/**
* Botão base do ZMMO. Camada de fundação (não instanciável direto — padrão
* "_Abstract" do Hyper, mas em C++).
*
* Divisão de responsabilidade (ARQUITETURA.md §3.3, exceção de UI):
* - CommonUI (UCommonButtonBase): input teclado/gamepad, foco, click.
* - Este C++: resolve QUAIS tokens usar (variante + tema via
* UZMMOThemeSubsystem::GetActiveUIStyle()) e reage à troca de tema.
* - O WBP que herda (UI_Button_Master): decide COMO pintar, recebendo os
* tokens resolvidos em BP_ApplyUIStyle.
*
* Hierarquia esperada: UUIButton_Base (C++ Abstract)
* → UI_Button_Base (WBP abstrato) → UI_Button_Master → UI_Button_<Feature>.
*/
UCLASS(Abstract, Blueprintable)
class ZMMO_API UUIButton_Base : public UCommonButtonBase
{
GENERATED_BODY()
public:
/** Variante visual; o designer escolhe no WBP/instância. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI Style")
EUIButtonVariant Variant = EUIButtonVariant::Primary;
/** Re-resolve os tokens do tema ativo e reaplica (chama BP_ApplyUIStyle). */
UFUNCTION(BlueprintCallable, Category = "UI Style")
void RefreshUIStyle();
protected:
virtual void NativePreConstruct() override;
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
/**
* Implementado no WBP: aplica os tokens resolvidos nos widgets visuais
* (Border/Text/etc.) que só o Blueprint conhece.
*/
UFUNCTION(BlueprintImplementableEvent, Category = "UI Style",
meta = (DisplayName = "Apply UI Style"))
void BP_ApplyUIStyle(const FUIStyleButton& Button, const FUIStyleButtonVariant& VariantStyle);
/** Seleciona o sub-struct da variante atual dentro de FUIStyleButton. */
const FUIStyleButtonVariant& ResolveVariant(const FUIStyleButton& Button) const;
private:
UFUNCTION()
void HandleThemeChanged(FName NewThemeId);
/** Evita rebind duplicado do delegate OnThemeChanged. */
bool bThemeBound = false;
};

View File

@@ -15,6 +15,8 @@ public class ZMMO : ModuleRules
"UMG",
"Slate",
"Niagara",
"CommonUI",
"CommonInput",
"ZeusNetwork"
});
@@ -30,6 +32,7 @@ public class ZMMO : ModuleRules
"ZMMO/Game/Modes",
"ZMMO/Game/Network",
"ZMMO/Game/UI",
"ZMMO/Game/UI/Widgets",
"ZMMO/Data",
"ZMMO/Data/Items",
"ZMMO/Data/Mobs",