feat(ui): UUIPanel_Base (UCommonUserWidget Abstract) data-driven por FUIStyle.Panel
Mesmo padrao do botao: C++ Abstract -> WBP concreto. PanelType (Primary/Secondary/Tertiary/Card) escolhe Bg/BgRaised/BgSunken/CardSelected; bRoundedBackground (RoundedBox + borda do tema); bUseSmallPadding. Background(UBorder) + Content(UNamedSlot) BindWidgetOptional. RefreshUIStyle resolve FUIStyle.Panel via UZMMOThemeSubsystem, reage a OnThemeChanged; BP_ApplyPanelStyle como hook. Compila OK. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
114
Source/ZMMO/Game/UI/Widgets/UIPanel_Base.cpp
Normal file
114
Source/ZMMO/Game/UI/Widgets/UIPanel_Base.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include "UIPanel_Base.h"
|
||||
|
||||
#include "ZMMOThemeSubsystem.h"
|
||||
#include "Engine/GameInstance.h"
|
||||
#include "Components/Border.h"
|
||||
#include "Components/NamedSlot.h"
|
||||
#include "Styling/SlateBrush.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const FUIStyle& ResolvePanelStyle(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; // design-time: defaults Aurora Arcana
|
||||
}
|
||||
}
|
||||
|
||||
void UUIPanel_Base::RefreshUIStyle()
|
||||
{
|
||||
if (!Background)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const FUIStyle Fallback;
|
||||
const FUIStyle& AS = ResolvePanelStyle(this, Fallback);
|
||||
const FUIStylePanel& P = AS.Panel;
|
||||
|
||||
FLinearColor Fill;
|
||||
FLinearColor Outline = P.BorderColor;
|
||||
switch (PanelType)
|
||||
{
|
||||
case EUIPanelType::Secondary: Fill = P.BgRaised; break;
|
||||
case EUIPanelType::Tertiary: Fill = P.BgSunken; break;
|
||||
case EUIPanelType::Card: Fill = P.CardSelectedBg; Outline = P.CardSelectedBorder; break;
|
||||
case EUIPanelType::Primary:
|
||||
case EUIPanelType::None:
|
||||
default: Fill = P.Bg; break;
|
||||
}
|
||||
|
||||
FSlateBrush Brush = Background->Background;
|
||||
Brush.TintColor = FSlateColor(Fill);
|
||||
if (bRoundedBackground)
|
||||
{
|
||||
const float R = bUseSmallPadding ? P.CornerRadiusSmall : P.CornerRadius;
|
||||
Brush.DrawAs = ESlateBrushDrawType::RoundedBox;
|
||||
Brush.OutlineSettings = FSlateBrushOutlineSettings(
|
||||
FVector4(R, R, R, R), FSlateColor(Outline), P.BorderWidth);
|
||||
Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius;
|
||||
}
|
||||
else
|
||||
{
|
||||
Brush.DrawAs = ESlateBrushDrawType::Box;
|
||||
Brush.OutlineSettings = FSlateBrushOutlineSettings(
|
||||
FVector4(0, 0, 0, 0), FSlateColor(Outline), P.BorderWidth);
|
||||
}
|
||||
Background->SetBrush(Brush);
|
||||
Background->SetPadding(bUseSmallPadding ? P.PaddingSmall : P.Padding);
|
||||
|
||||
BP_ApplyPanelStyle(P);
|
||||
}
|
||||
|
||||
void UUIPanel_Base::NativePreConstruct()
|
||||
{
|
||||
Super::NativePreConstruct();
|
||||
RefreshUIStyle();
|
||||
}
|
||||
|
||||
void UUIPanel_Base::NativeConstruct()
|
||||
{
|
||||
Super::NativeConstruct();
|
||||
|
||||
if (!bThemeBound)
|
||||
{
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
|
||||
{
|
||||
Theme->OnThemeChanged.AddDynamic(this, &UUIPanel_Base::HandleThemeChanged);
|
||||
bThemeBound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
RefreshUIStyle();
|
||||
}
|
||||
|
||||
void UUIPanel_Base::NativeDestruct()
|
||||
{
|
||||
if (bThemeBound)
|
||||
{
|
||||
if (const UGameInstance* GI = GetGameInstance())
|
||||
{
|
||||
if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem<UZMMOThemeSubsystem>())
|
||||
{
|
||||
Theme->OnThemeChanged.RemoveDynamic(this, &UUIPanel_Base::HandleThemeChanged);
|
||||
}
|
||||
}
|
||||
bThemeBound = false;
|
||||
}
|
||||
Super::NativeDestruct();
|
||||
}
|
||||
|
||||
void UUIPanel_Base::HandleThemeChanged(FName /*NewThemeId*/)
|
||||
{
|
||||
RefreshUIStyle();
|
||||
}
|
||||
65
Source/ZMMO/Game/UI/Widgets/UIPanel_Base.h
Normal file
65
Source/ZMMO/Game/UI/Widgets/UIPanel_Base.h
Normal file
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "CommonUserWidget.h"
|
||||
#include "UI/UIStyleTypes.h"
|
||||
#include "UI/UIStyleTokens.h"
|
||||
#include "UIPanel_Base.generated.h"
|
||||
|
||||
class UBorder;
|
||||
class UNamedSlot;
|
||||
|
||||
/**
|
||||
* Painel base do ZMMO — mesmo padrão do UUIButton_Base, mas container.
|
||||
* Fundação CommonUI (UCommonUserWidget). Camada Abstract; o WBP concreto
|
||||
* (UI_Panel_Master) herda DIRETO desta classe C++ (UMG não encadeia árvores
|
||||
* de WBP — ver ARQUITETURA.md §3.3).
|
||||
*
|
||||
* Visual data-driven por FUIStyle.Panel (UZMMOThemeSubsystem). Designers
|
||||
* injetam o conteúdo no NamedSlot "Content".
|
||||
*/
|
||||
UCLASS(Abstract, Blueprintable)
|
||||
class ZMMO_API UUIPanel_Base : public UCommonUserWidget
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
/** Tipo do painel — escolhe Bg/BgRaised/BgSunken/Card de FUIStylePanel. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel")
|
||||
EUIPanelType PanelType = EUIPanelType::Primary;
|
||||
|
||||
/** Arredonda o Background (RoundedBox) com a borda do tema. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel")
|
||||
bool bRoundedBackground = true;
|
||||
|
||||
/** Usa o padding "pequeno" do tema (PaddingSmall) em vez de Padding. */
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel")
|
||||
bool bUseSmallPadding = false;
|
||||
|
||||
/** Re-resolve os tokens do tema ativo e reaplica no Background. */
|
||||
UFUNCTION(BlueprintCallable, Category = "UI Style")
|
||||
void RefreshUIStyle();
|
||||
|
||||
protected:
|
||||
virtual void NativePreConstruct() override;
|
||||
virtual void NativeConstruct() override;
|
||||
virtual void NativeDestruct() override;
|
||||
|
||||
/** Hook opcional: o WBP pode estender/sobrescrever a aplicação visual. */
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = "UI Style",
|
||||
meta = (DisplayName = "Apply Panel Style"))
|
||||
void BP_ApplyPanelStyle(const FUIStylePanel& Panel);
|
||||
|
||||
/** Widgets visuais opcionais. */
|
||||
UPROPERTY(meta = (BindWidgetOptional))
|
||||
TObjectPtr<UBorder> Background;
|
||||
|
||||
UPROPERTY(meta = (BindWidgetOptional))
|
||||
TObjectPtr<UNamedSlot> Content;
|
||||
|
||||
private:
|
||||
UFUNCTION()
|
||||
void HandleThemeChanged(FName NewThemeId);
|
||||
|
||||
bool bThemeBound = false;
|
||||
};
|
||||
Reference in New Issue
Block a user