From ab74ef8b17206df9117f016650bd7e08bc2d5a43 Mon Sep 17 00:00:00 2001 From: Mateus Rodrigues Date: Mon, 18 May 2026 21:28:45 -0300 Subject: [PATCH] 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) --- Config/DefaultEngine.ini | 2 + Source/ZMMO/Data/UI/UIStyleTypes.h | 10 +++ Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp | 89 +++++++++++++++++++ Source/ZMMO/Game/UI/Widgets/UIButton_Base.h | 59 ++++++++++++ Source/ZMMO/ZMMO.Build.cs | 3 + 5 files changed, 163 insertions(+) create mode 100644 Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp create mode 100644 Source/ZMMO/Game/UI/Widgets/UIButton_Base.h diff --git a/Config/DefaultEngine.ini b/Config/DefaultEngine.ini index cbad2e0..ce6b91b 100644 --- a/Config/DefaultEngine.ini +++ b/Config/DefaultEngine.ini @@ -75,6 +75,8 @@ DefaultGraphicsPerformance=Maximum AppliedDefaultGraphicsPerformance=Maximum [/Script/Engine.Engine] +; CommonUI: viewport client que roteia input (teclado/gamepad) e foco para a UI. +GameViewportClientClassName=/Script/CommonUI.CommonGameViewportClient +ActiveGameNameRedirects=(OldGameName="TP_ThirdPerson",NewGameName="/Script/ZMMO") +ActiveGameNameRedirects=(OldGameName="/Script/TP_ThirdPerson",NewGameName="/Script/ZMMO") ; Redirects do template antigo para a nova arquitectura (Game/Modes/Entity/Controller). diff --git a/Source/ZMMO/Data/UI/UIStyleTypes.h b/Source/ZMMO/Data/UI/UIStyleTypes.h index 4446300..9dd844f 100644 --- a/Source/ZMMO/Data/UI/UIStyleTypes.h +++ b/Source/ZMMO/Data/UI/UIStyleTypes.h @@ -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 diff --git a/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp new file mode 100644 index 0000000..431e66b --- /dev/null +++ b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp @@ -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()) + { + 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()) + { + 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()) + { + Theme->OnThemeChanged.RemoveDynamic(this, &UUIButton_Base::HandleThemeChanged); + } + } + bThemeBound = false; + } + + Super::NativeDestruct(); +} + +void UUIButton_Base::HandleThemeChanged(FName /*NewThemeId*/) +{ + RefreshUIStyle(); +} diff --git a/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h new file mode 100644 index 0000000..6b1c934 --- /dev/null +++ b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h @@ -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_. + */ +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; +}; diff --git a/Source/ZMMO/ZMMO.Build.cs b/Source/ZMMO/ZMMO.Build.cs index c1f30f3..cf1f3c9 100644 --- a/Source/ZMMO/ZMMO.Build.cs +++ b/Source/ZMMO/ZMMO.Build.cs @@ -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",