diff --git a/Content/ZMMO/Data/UI/DT_UI_Styles.uasset b/Content/ZMMO/Data/UI/DT_UI_Styles.uasset index 2a65db1..a85ab85 100644 Binary files a/Content/ZMMO/Data/UI/DT_UI_Styles.uasset and b/Content/ZMMO/Data/UI/DT_UI_Styles.uasset differ diff --git a/Content/ZMMO/UI/Shared/UI_Button_Master_New.uasset b/Content/ZMMO/UI/Shared/UI_Button_Master_New.uasset new file mode 100644 index 0000000..a2e21ba Binary files /dev/null and b/Content/ZMMO/UI/Shared/UI_Button_Master_New.uasset differ diff --git a/Content/ZMMO/UI/Shared/UI_Panel_Master.uasset b/Content/ZMMO/UI/Shared/UI_Panel_Master.uasset index 2670a64..0ea3506 100644 Binary files a/Content/ZMMO/UI/Shared/UI_Panel_Master.uasset and b/Content/ZMMO/UI/Shared/UI_Panel_Master.uasset differ diff --git a/Source/ZMMO/Data/UI/UIStyleTokens.h b/Source/ZMMO/Data/UI/UIStyleTokens.h index 68ce067..07a9835 100644 --- a/Source/ZMMO/Data/UI/UIStyleTokens.h +++ b/Source/ZMMO/Data/UI/UIStyleTokens.h @@ -3,6 +3,7 @@ #include "CoreMinimal.h" #include "Fonts/SlateFontInfo.h" #include "Styling/SlateBrush.h" +#include "Styling/SlateTypes.h" #include "Layout/Margin.h" #include "Templates/SubclassOf.h" #include "Engine/Texture2D.h" @@ -195,117 +196,13 @@ struct ZMMO_API FUITextStyle }; // ===================================================================== -// FUIStyleButton — padrão multi-map (Hyper-style). 3 sub-mapas com a MESMA -// chave (nome da variante: "Primary", "Secondary", "Danger", "Ghost", ou -// customizada). UUIButton_Base.Variant é FName e busca em cada sub-mapa. -// O struct FUIStyleButtonVariant (composto, FLAT) permanece com a forma -// antiga — assim o hook BP_ApplyUIStyle dos WBP_Master continua funcional. +// FUIStyleButton — padrão Hyper "Buttons": 7 sub-mapas independentes +// indexados pela MESMA chave FName de variante (autor define livremente: +// "Default", "Square", "Topbar", "Home_Main_Menu", ...). UUIButton_Base.Variant +// é FName e busca o pedaço necessário em cada sub-mapa. ButtonStyle traz +// FButtonStyle do Slate completo (Normal/Hovered/Pressed/Disabled como +// FSlateBrush, Foregrounds, Padding, Sounds). // ===================================================================== -USTRUCT(BlueprintType) -struct ZMMO_API FUIStyleButtonBackground -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgNormal = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgHover = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgPressed = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgDisabled = FLinearColor(0.f, 0.f, 0.f, 0.42f); - - /** Textura opcional como background (Hyper-style). */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TObjectPtr BackgroundTexture = nullptr; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FMargin BackgroundMargin = FMargin(8.f); -}; - -USTRUCT(BlueprintType) -struct ZMMO_API FUIStyleButtonStroke -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BorderNormal = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BorderHover = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button", meta = (ClampMin = "0")) - float BorderWidth = 1.f; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button", meta = (ClampMin = "0")) - float CornerRadius = 8.f; -}; - -USTRUCT(BlueprintType) -struct ZMMO_API FUIStyleButtonFont -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor TextColor = FLinearColor::White; - - /** CommonTextStyle define fonte/tamanho/peso; TextColor sobrescreve a cor. */ - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TSubclassOf TextStyle; -}; - -/** - * View FLAT composta da variante de botão (Background + Stroke + Font). - * Mantida com a forma antiga (BgNormal/BgHover/.../TextStyle no topo) para - * NÃO QUEBRAR o hook BP_ApplyUIStyle nos WBP_Master existentes. É construída - * pelo UUIButton_Base::ResolveVariant a partir dos 3 sub-mapas do tema. - */ -USTRUCT(BlueprintType) -struct ZMMO_API FUIStyleButtonVariant -{ - GENERATED_BODY() - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgNormal = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgHover = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgPressed = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BgDisabled = FLinearColor(0.f, 0.f, 0.f, 0.42f); - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BorderNormal = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor BorderHover = FLinearColor::Transparent; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FLinearColor TextColor = FLinearColor::White; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TSubclassOf TextStyle; - - // Campos extras vindos das sub-categorias (background texture + stroke): - UPROPERTY(BlueprintReadOnly, Category = "UI Style|Button") - TObjectPtr BackgroundTexture = nullptr; - - UPROPERTY(BlueprintReadOnly, Category = "UI Style|Button") - FMargin BackgroundMargin = FMargin(8.f); - - UPROPERTY(BlueprintReadOnly, Category = "UI Style|Button") - float BorderWidth = 1.f; - - UPROPERTY(BlueprintReadOnly, Category = "UI Style|Button") - float CornerRadius = 8.f; -}; - USTRUCT(BlueprintType) struct ZMMO_API FUIStyleButton { @@ -313,163 +210,103 @@ struct ZMMO_API FUIStyleButton FUIStyleButton() { - // ---- Backgrounds (Primary/Secondary/Danger/Ghost) ---- - FUIStyleButtonBackground PriBg; - PriBg.BgNormal = FLinearColor(FColor(201, 167, 90)); // gold - PriBg.BgHover = FLinearColor(FColor(231, 200, 115)); // gold-hi - PriBg.BgPressed = FLinearColor(FColor(201, 167, 90)); - PriBg.BgDisabled = FLinearColor(FColor(201, 167, 90, 107)); - Backgrounds.Add(TEXT("Primary"), PriBg); + // Defaults "no draw" pra não pintar branco quando o brush estiver vazio + // (regra Hyper — ver feedback_slatebrush_empty_white). Autor preenche + // no DT_UI_Styles. + FButtonStyle DefaultStyle; + DefaultStyle.Normal.DrawAs = ESlateBrushDrawType::NoDrawType; + DefaultStyle.Hovered.DrawAs = ESlateBrushDrawType::NoDrawType; + DefaultStyle.Pressed.DrawAs = ESlateBrushDrawType::NoDrawType; + DefaultStyle.Disabled.DrawAs = ESlateBrushDrawType::NoDrawType; + ButtonStyle.Add(TEXT("Default"), DefaultStyle); - FUIStyleButtonBackground SecBg; - SecBg.BgNormal = FLinearColor(FColor(17, 24, 42)); // panel-2 - SecBg.BgHover = FLinearColor(FColor(22, 32, 58)); - SecBg.BgPressed = FLinearColor(FColor(17, 24, 42)); - Backgrounds.Add(TEXT("Secondary"), SecBg); + FSlateBrush DefaultStroke; + DefaultStroke.DrawAs = ESlateBrushDrawType::NoDrawType; + ButtonStroke.Add(TEXT("Default"), DefaultStroke); - FUIStyleButtonBackground DngBg; - DngBg.BgNormal = FLinearColor(FColor(217, 92, 92, 36)); - DngBg.BgHover = FLinearColor(FColor(217, 92, 92, 66)); - DngBg.BgPressed = FLinearColor(FColor(217, 92, 92, 36)); - Backgrounds.Add(TEXT("Danger"), DngBg); + ButtonFont.Add(TEXT("Default"), FSlateFontInfo()); - FUIStyleButtonBackground GhoBg; - GhoBg.BgNormal = FLinearColor::Transparent; - GhoBg.BgHover = FLinearColor(FColor(22, 32, 58, 128)); - GhoBg.BgPressed = FLinearColor::Transparent; - Backgrounds.Add(TEXT("Ghost"), GhoBg); + ButtonTextColorRegular.Add(TEXT("Default"), FLinearColor::White); + ButtonTextColorHovered.Add(TEXT("Default"), FLinearColor::White); + ButtonTextColorSelected.Add(TEXT("Default"), FLinearColor::White); - // ---- Strokes ---- - FUIStyleButtonStroke PriS; - PriS.BorderNormal = FLinearColor(FColor(201, 167, 90)); - PriS.BorderHover = FLinearColor(FColor(231, 200, 115)); - Strokes.Add(TEXT("Primary"), PriS); - - FUIStyleButtonStroke SecS; - SecS.BorderNormal = FLinearColor(FColor(58, 75, 120)); - SecS.BorderHover = FLinearColor(FColor(78, 163, 255)); - Strokes.Add(TEXT("Secondary"), SecS); - - FUIStyleButtonStroke DngS; - DngS.BorderNormal = FLinearColor(FColor(217, 92, 92)); - DngS.BorderHover = FLinearColor(FColor(217, 92, 92)); - Strokes.Add(TEXT("Danger"), DngS); - - FUIStyleButtonStroke GhoS; - GhoS.BorderNormal = FLinearColor(FColor(58, 75, 120, 140)); - GhoS.BorderHover = FLinearColor(FColor(78, 163, 255)); - Strokes.Add(TEXT("Ghost"), GhoS); - - // ---- Fonts ---- - FUIStyleButtonFont PriF; PriF.TextColor = FLinearColor(FColor(10, 10, 18)); - Fonts.Add(TEXT("Primary"), PriF); - FUIStyleButtonFont SecF; SecF.TextColor = FLinearColor(FColor(244, 240, 230)); - Fonts.Add(TEXT("Secondary"), SecF); - FUIStyleButtonFont DngF; DngF.TextColor = FLinearColor(FColor(240, 182, 182)); - Fonts.Add(TEXT("Danger"), DngF); - FUIStyleButtonFont GhoF; GhoF.TextColor = FLinearColor(FColor(174, 182, 200)); - Fonts.Add(TEXT("Ghost"), GhoF); + ButtonIconColor.Add(TEXT("Default"), FLinearColor::White); } - /** Cores/textura de fundo por variante (chave FName). */ + /** FButtonStyle do Slate por variante: Normal/Hovered/Pressed/Disabled + * como FSlateBrush completo + Foregrounds + Padding + Sounds. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TMap Backgrounds; + TMap ButtonStyle; - /** Borda (cor, espessura, raio) por variante. */ + /** Stroke/contorno como brush independente (texturizável). Hoje o + * UUIButton_Base não consome este campo automaticamente — quem precisa + * de stroke decora o FSlateBrush dentro de ButtonStyle.Normal via + * OutlineSettings. Reservado pra evolução com 2 Borders empilhados. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TMap Strokes; + TMap ButtonStroke; - /** Tipografia (cor de texto, CommonTextStyle) por variante. */ + /** Fonte do texto por variante. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TMap Fonts; - - // Globais comuns às variantes: - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - FMargin Padding = FMargin(22.f, 12.f); + TMap ButtonFont; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - float MinHeight = 48.f; + TMap ButtonTextColorRegular; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - float HoverScale = 1.02f; + TMap ButtonTextColorHovered; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - float PressedScale = 0.98f; + TMap ButtonTextColorSelected; - /** Tamanho por silhueta (Square/Rectangle/Topbar/Header). */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Button") - TMap ShapeSizes; + TMap ButtonIconColor; }; /** - * Espelha 1:1 o Struct_UI_Style_Panels do Hyper: só os dois mapas de brush - * (fundo + contorno) indexados por EUIPanelTexture. É o que o UI_Panel_Master - * do Hyper expõe editável na instância (Details). EditAnywhere/ReadWrite para - * o designer ajustar brush por widget; o tema (DT) só faz seed/fallback. + * Override manual por instância (modo bUseTheme = false). 3 brushes diretos + * pros 3 Borders do painel — designer edita o brush bruto no Details. + * Default = NoDrawType pra não pintar branco quando vazio (regra Hyper). */ USTRUCT(BlueprintType) struct ZMMO_API FUIPanelBrushSet { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel|Texture") - TMap PanelBackground; + FUIPanelBrushSet() + { + PanelBackground.DrawAs = ESlateBrushDrawType::NoDrawType; + PanelOutline.DrawAs = ESlateBrushDrawType::NoDrawType; + PanelOutlineEffect.DrawAs = ESlateBrushDrawType::NoDrawType; + } - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel|Texture") - TMap PanelOutline; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel|Brush") + FSlateBrush PanelBackground; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel|Brush") + FSlateBrush PanelOutline; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel|Brush") + FSlateBrush PanelOutlineEffect; }; +/** + * Espelha 1:1 o Struct_UI_Style_Panels do Hyper, agora com 3 brushes por + * EUIPanelTexture: fundo, contorno e efeito sobre o contorno. Tudo + * data-driven via brush no DT_UI_Styles. + */ USTRUCT(BlueprintType) struct ZMMO_API FUIStylePanel { GENERATED_BODY() - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor Bg = FLinearColor(FColor(12, 18, 34, 235)); // Panel - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor BgRaised = FLinearColor(FColor(17, 24, 42)); // Panel2 - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor BgSunken = FLinearColor(FColor(14, 20, 36)); // Panel3 - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor BorderColor = FLinearColor(FColor(58, 75, 120)); - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor BorderSoftColor = FLinearColor(FColor(58, 75, 120, 140)); - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - float CornerRadius = 12.f; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - float CornerRadiusSmall = 10.f; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - float BorderWidth = 1.f; - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FMargin Padding = FMargin(30.f); - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FMargin PaddingSmall = FMargin(20.f); - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor CardSelectedBorder = FLinearColor(FColor(201, 167, 90)); // Accent - - UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel") - FLinearColor CardSelectedBg = FLinearColor(FColor(24, 32, 58)); - - /** - * Modo texturizado (espelha Struct_UI_Style_Panels do Hyper): brush por - * EUIPanelTexture. PanelBackground = fundo; PanelOutline = contorno. - * Se vazio p/ a chave, o painel usa o modo cor (RoundedBox) acima. - */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture") TMap PanelBackground; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture") TMap PanelOutline; + + UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "UI Style|Panel|Texture") + TMap PanelOutlineEffect; }; USTRUCT(BlueprintType) diff --git a/Source/ZMMO/Data/UI/UIStyleTypes.h b/Source/ZMMO/Data/UI/UIStyleTypes.h index 826a9cd..ffcef81 100644 --- a/Source/ZMMO/Data/UI/UIStyleTypes.h +++ b/Source/ZMMO/Data/UI/UIStyleTypes.h @@ -66,6 +66,7 @@ enum class EUIPanelTexture : uint8 Rectangle_Vertical_03 UMETA(DisplayName = "Rectangle Vertical 03"), Rectangle_Vertical_04 UMETA(DisplayName = "Rectangle Vertical 04"), Rectangle_Square_01 UMETA(DisplayName = "Rectangle Square 01"), + Rectangle_Square_Gradient_01 UMETA(DisplayName = "Rectangle Square Gradient 01"), Vertical_Footer_01 UMETA(DisplayName = "Vertical Footer 01") }; diff --git a/Source/ZMMO/Game/UI/FrontEnd/UIServerCard_Base.cpp b/Source/ZMMO/Game/UI/FrontEnd/UIServerCard_Base.cpp index 8a357ac..bd87530 100644 --- a/Source/ZMMO/Game/UI/FrontEnd/UIServerCard_Base.cpp +++ b/Source/ZMMO/Game/UI/FrontEnd/UIServerCard_Base.cpp @@ -9,12 +9,11 @@ void UUIServerCard_Base::NativePreConstruct() { Super::NativePreConstruct(); - // Reaplica tema do botao antes de qualquer SetIsEnabled — garante que o - // background da variante "Primary" pinta tanto em Normal quanto Disabled. - if (Btn_Enter) - { - Btn_Enter->RefreshUIStyle(); - } + // TODO(ui-system): reativar quando UUIButton_Base voltar a ter RefreshUIStyle. + // if (Btn_Enter) + // { + // Btn_Enter->RefreshUIStyle(); + // } } void UUIServerCard_Base::NativeConstruct() @@ -25,10 +24,11 @@ void UUIServerCard_Base::NativeConstruct() Btn_Enter->OnClicked().AddUObject(this, &UUIServerCard_Base::HandleEnterClicked); bBound = true; } - if (Btn_Enter) - { - Btn_Enter->RefreshUIStyle(); - } + // TODO(ui-system): reativar quando UUIButton_Base voltar a ter RefreshUIStyle. + // if (Btn_Enter) + // { + // Btn_Enter->RefreshUIStyle(); + // } } void UUIServerCard_Base::NativeDestruct() @@ -69,10 +69,11 @@ void UUIServerCard_Base::SetFromEntry(const FZMMOWorldEntry& InEntry) // o usuario pode entrar no Lobby pra ver a lista de personagens, criar/ // deletar. O gate de "entrar no mundo" fica no proprio Lobby (botao // "Entrar no Servidor"), que checa World.State antes do handoff. - if (Btn_Enter) - { - Btn_Enter->RefreshUIStyle(); - } + // TODO(ui-system): reativar quando UUIButton_Base voltar a ter RefreshUIStyle. + // if (Btn_Enter) + // { + // Btn_Enter->RefreshUIStyle(); + // } } void UUIServerCard_Base::HandleEnterClicked() diff --git a/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp index 51bb889..d9c7d61 100644 --- a/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp +++ b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.cpp @@ -1,434 +1,28 @@ #include "UIButton_Base.h" -#include "ZMMOThemeSubsystem.h" -#include "Engine/GameInstance.h" -#include "Engine/World.h" -#include "TimerManager.h" -#include "Components/Border.h" -#include "Styling/SlateBrush.h" -#include "Components/TextBlock.h" -#include "Components/Image.h" -#include "Components/SizeBox.h" -#include "Components/ScaleBox.h" -#include "Components/OverlaySlot.h" -#include "CommonTextBlock.h" -#include "CommonActionWidget.h" +#include "UI/UIStyleRow.h" +#include "UI/UIStyleTokens.h" +#include "Engine/DataTable.h" -namespace +const FUIStyle* UUIButton_Base::GetActiveUIStyle(FName ThemeId) const { - /** Resolve o FUIStyle ativo; fallback p/ defaults (preview de designer). */ - const FUIStyle& ResolveActiveStyle(const UUserWidget* Widget, const FUIStyle& Fallback) + const UDataTable* DT = LoadObject(nullptr, + TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles")); + if (!DT) { - 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 + return nullptr; } + + if (const FUIStyleRow* Row = DT->FindRow( + ThemeId, TEXT("UUIButton_Base::GetActiveUIStyle"), false)) + { + return &Row->Style; + } + return nullptr; } -FUIStyleButtonVariant UUIButton_Base::ResolveVariant(const FUIStyleButton& Button) const +const FUIStyleButton* UUIButton_Base::GetActiveButtonStyle(FName ThemeId) const { - // Compõe FLAT a partir dos 3 sub-mapas do tema (Backgrounds/Strokes/Fonts). - // Fallback inline → Defaults (constructor de FUIStyleButton popula - // Primary/Secondary/Danger/Ghost com defaults Aurora Arcana — GC-safe). - static const FUIStyleButton Defaults; - FUIStyleButtonVariant V; - - const FUIStyleButtonBackground* BG = Button.Backgrounds.Find(Variant); - if (!BG) { BG = Defaults.Backgrounds.Find(Variant); } - if (!BG) { BG = Defaults.Backgrounds.Find(TEXT("Primary")); } - if (BG) - { - V.BgNormal = BG->BgNormal; - V.BgHover = BG->BgHover; - V.BgPressed = BG->BgPressed; - V.BgDisabled = BG->BgDisabled; - V.BackgroundTexture = BG->BackgroundTexture; - V.BackgroundMargin = BG->BackgroundMargin; - } - - const FUIStyleButtonStroke* ST = Button.Strokes.Find(Variant); - if (!ST) { ST = Defaults.Strokes.Find(Variant); } - if (!ST) { ST = Defaults.Strokes.Find(TEXT("Primary")); } - if (ST) - { - V.BorderNormal = ST->BorderNormal; - V.BorderHover = ST->BorderHover; - V.BorderWidth = ST->BorderWidth; - V.CornerRadius = ST->CornerRadius; - } - - const FUIStyleButtonFont* F = Button.Fonts.Find(Variant); - if (!F) { F = Defaults.Fonts.Find(Variant); } - if (!F) { F = Defaults.Fonts.Find(TEXT("Primary")); } - if (F) - { - V.TextColor = F->TextColor; - V.TextStyle = F->TextStyle; - } - return V; -} - -TArray UUIButton_Base::GetVariantOptions() const -{ - TArray Options; - for (const TCHAR* N : { TEXT("Primary"), TEXT("Secondary"), TEXT("Danger"), TEXT("Ghost") }) - { - Options.Add(N); - } - if (const UDataTable* DT = LoadObject(nullptr, - TEXT("/Game/ZMMO/Data/UI/DT_UI_Styles.DT_UI_Styles"))) - { - if (const FUIStyleRow* Row = DT->FindRow( - FName(TEXT("Default")), TEXT("UIButtonVariantOptions"), false)) - { - for (const TPair& P : Row->Style.Button.Backgrounds) { Options.AddUnique(P.Key.ToString()); } - for (const TPair& P : Row->Style.Button.Strokes) { Options.AddUnique(P.Key.ToString()); } - for (const TPair& P : Row->Style.Button.Fonts) { Options.AddUnique(P.Key.ToString()); } - } - } - return Options; -} - -// ---- Hyper "Set Button Text" ---- -void UUIButton_Base::SetButtonText(FText InText) -{ - if (!ButtonText) - { - return; - } - const FText Final = bUppercaseText - ? FText::FromString(InText.ToString().ToUpper()) - : InText; - ButtonText->SetText(Final); -} - -// ---- Hyper "Set Number Text" ---- -void UUIButton_Base::SetNumberText() -{ - if (!Number_Text) - { - return; - } - if (bShowNumberText) - { - Number_Text->SetText(FText::AsNumber(NumberTextAmount)); - Number_Text->SetVisibility(ESlateVisibility::Visible); - } - else - { - Number_Text->SetVisibility(ESlateVisibility::Hidden); - } -} - -// ---- Hyper "Set Icon" ---- -void UUIButton_Base::SetIcon() -{ - if (bUseIconInsteadOfText) - { - if (Image_Icon) - { - if (IconImage) - { - Image_Icon->SetBrushResourceObject(IconImage); - } - Image_Icon->SetVisibility(ESlateVisibility::Visible); - } - if (ButtonText) - { - ButtonText->SetVisibility(ESlateVisibility::Collapsed); - } - } - else - { - if (Image_Icon) - { - Image_Icon->SetVisibility(ESlateVisibility::Collapsed); - } - if (ButtonText) - { - ButtonText->SetVisibility(ESlateVisibility::Visible); - } - } -} - -// ---- Hyper "Set Sizebox Master Dimmensions" ---- -void UUIButton_Base::ApplySizeBox() -{ - if (bDoNotOverrideWithSizebox || !SizeBox_Master) - { - return; - } - SizeBox_Master->SetHeightOverride(InHeightOverride); - SizeBox_Master->SetWidthOverride(InWidthOverride); -} - -// ---- Hyper "Set InputAction Style" ---- -void UUIButton_Base::ApplyInputActionStyle() -{ - // InputActionWidget é privado em UCommonButtonBase (bind interno). Pega por - // nome — o widget do WBP chama-se "InputActionWidget" (bind do CommonUI). - UCommonActionWidget* IAW = Cast( - GetWidgetFromName(TEXT("InputActionWidget"))); - if (!IAW) - { - return; - } - - if (bShowInputActionWidget) - { - IAW->SetVisibility(ESlateVisibility::Visible); - IAW->SetIsEnabled(true); - } - else - { - IAW->SetVisibility(ESlateVisibility::Collapsed); - IAW->SetIsEnabled(false); - } - - if (UOverlaySlot* OS = Cast(IAW->Slot)) - { - OS->SetPadding(InputPadding); - OS->SetHorizontalAlignment(InputHorzAlignment); - OS->SetVerticalAlignment(InputVertAlignment); - } -} - -// ---- Hyper "Initialize Button" (orquestrador) ---- -void UUIButton_Base::InitializeButton() -{ - SetButtonText(ButtonTextValue); - SetNumberText(); - SetIcon(); - ApplySizeBox(); - RefreshUIStyle(); -} - -// ---- Hyper "Update Button Style" / "Set Brush" → nossa camada FUIStyle ---- -void UUIButton_Base::RefreshUIStyle() -{ - const FUIStyle Fallback; // defaults do struct = paleta Aurora Arcana - const FUIStyle& ActiveStyle = ResolveActiveStyle(this, Fallback); - const FUIStyleButtonVariant& VariantStyle = ResolveVariant(ActiveStyle.Button); - - // Fundo + borda no estado Normal (hover/pressed/disabled via NativeOn*). - ApplyVisualState(EUIButtonVisual::Normal); - - if (ButtonText) - { - // Tipografia: CommonTextStyle da variante (padrão Hyper/CommonUI). - if (VariantStyle.TextStyle) - { - ButtonText->SetStyle(VariantStyle.TextStyle); - } - // Cor: FUIStyle manda na cor por tema (sobrepõe o CommonTextStyle). - ButtonText->SetColorAndOpacity(FSlateColor(VariantStyle.TextColor)); - - // Alinhamento L/C/R dentro da largura do botão. - ButtonText->SetJustification(TextAlign); - } - - // Texto adapta ao tamanho do botão (ScaleToFit) ou usa tamanho fixo. - if (TextScaleBox) - { - TextScaleBox->SetStretch(bAutoSizeText ? EStretch::ScaleToFit : EStretch::None); - - // Posiciona o bloco de texto L/C/R dentro do botão (slot do Overlay). - if (UOverlaySlot* OS = Cast(TextScaleBox->Slot)) - { - EHorizontalAlignment H = HAlign_Center; - switch (TextAlign) - { - case ETextJustify::Left: H = HAlign_Left; break; - case ETextJustify::Right: H = HAlign_Right; break; - default: H = HAlign_Center; break; - } - OS->SetHorizontalAlignment(H); - OS->SetVerticalAlignment(VAlign_Center); - } - } - - BP_ApplyUIStyle(ActiveStyle.Button, VariantStyle); -} - -void UUIButton_Base::ApplyVisualState(EUIButtonVisual State) -{ - if (!Background) - { - return; - } - const FUIStyle Fallback; - const FUIStyle& AS = ResolveActiveStyle(this, Fallback); - const FUIStyleButtonVariant& V = ResolveVariant(AS.Button); - - FLinearColor Fill, Outline; - switch (State) - { - case EUIButtonVisual::Hovered: Fill = V.BgHover; Outline = V.BorderHover; break; - case EUIButtonVisual::Pressed: Fill = V.BgPressed; Outline = V.BorderHover; break; - case EUIButtonVisual::Disabled: Fill = V.BgDisabled; Outline = V.BorderNormal; break; - default: Fill = V.BgNormal; Outline = V.BorderNormal; break; - } - - FSlateBrush Brush = Background->Background; - Brush.TintColor = FSlateColor(Fill); - if (bRoundedBackground) - { - // CornerRadius/BorderWidth agora vêm da variante composta (Stroke). - const float R = V.CornerRadius; - Brush.DrawAs = ESlateBrushDrawType::RoundedBox; - Brush.OutlineSettings = FSlateBrushOutlineSettings( - FVector4(R, R, R, R), FSlateColor(Outline), V.BorderWidth); - Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius; - } - else - { - Brush.DrawAs = ESlateBrushDrawType::Box; - Brush.OutlineSettings = FSlateBrushOutlineSettings( - FVector4(0, 0, 0, 0), FSlateColor(Outline), V.BorderWidth); - } - Background->SetBrush(Brush); -} - -void UUIButton_Base::NativeOnHovered() -{ - Super::NativeOnHovered(); - ApplyVisualState(EUIButtonVisual::Hovered); -} - -void UUIButton_Base::NativeOnUnhovered() -{ - Super::NativeOnUnhovered(); - ApplyVisualState(EUIButtonVisual::Normal); -} - -void UUIButton_Base::NativeOnPressed() -{ - Super::NativeOnPressed(); - ApplyVisualState(EUIButtonVisual::Pressed); -} - -void UUIButton_Base::NativeOnReleased() -{ - Super::NativeOnReleased(); - ApplyVisualState(IsHovered() ? EUIButtonVisual::Hovered : EUIButtonVisual::Normal); -} - -void UUIButton_Base::NativeOnEnabled() -{ - Super::NativeOnEnabled(); - ApplyVisualState(EUIButtonVisual::Normal); -} - -void UUIButton_Base::NativeOnDisabled() -{ - Super::NativeOnDisabled(); - ApplyVisualState(EUIButtonVisual::Disabled); -} - -void UUIButton_Base::NativePreConstruct() -{ - Super::NativePreConstruct(); - InitializeButton(); - ApplyInputActionStyle(); -} - -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; - } - } - } - - InitializeButton(); - ApplyInputActionStyle(); - - if (bDeactivatedOnConstructWithTimeout && Timeout > 0.f) - { - StartDeactivateTimeout(); - } -} - -void UUIButton_Base::NativeDestruct() -{ - if (UWorld* World = GetWorld()) - { - World->GetTimerManager().ClearTimer(InactivityTimer); - World->GetTimerManager().ClearTimer(TimerTickHandle); - } - - if (bThemeBound) - { - if (const UGameInstance* GI = GetGameInstance()) - { - if (UZMMOThemeSubsystem* Theme = GI->GetSubsystem()) - { - Theme->OnThemeChanged.RemoveDynamic(this, &UUIButton_Base::HandleThemeChanged); - } - } - bThemeBound = false; - } - - Super::NativeDestruct(); -} - -// ---- Hyper "Deactivate Button On Timeout" ---- -void UUIButton_Base::StartDeactivateTimeout() -{ - UWorld* World = GetWorld(); - if (!World) - { - return; - } - - SetIsEnabled(false); - TimeRemaining = Timeout; - - World->GetTimerManager().SetTimer( - InactivityTimer, this, &UUIButton_Base::HandleTimeoutFinished, Timeout, false); - - if (TimeUpdateFrequency > 0.f) - { - World->GetTimerManager().SetTimer( - TimerTickHandle, this, &UUIButton_Base::HandleTimerTick, - TimeUpdateFrequency, true); - } -} - -void UUIButton_Base::HandleTimeoutFinished() -{ - if (UWorld* World = GetWorld()) - { - World->GetTimerManager().ClearTimer(TimerTickHandle); - } - TimeRemaining = 0.f; - SetIsEnabled(true); - OnButtonActivatedByTimeout.Broadcast(); -} - -void UUIButton_Base::HandleTimerTick() -{ - TimeRemaining = FMath::Max(0.f, TimeRemaining - TimeUpdateFrequency); - OnButtonTimerUpdated.Broadcast(TimeRemaining); -} - -void UUIButton_Base::HandleThemeChanged(FName /*NewThemeId*/) -{ - RefreshUIStyle(); + const FUIStyle* UIStyle = GetActiveUIStyle(ThemeId); + return UIStyle ? &UIStyle->Button : nullptr; } diff --git a/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h index cdc0415..781c427 100644 --- a/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h +++ b/Source/ZMMO/Game/UI/Widgets/UIButton_Base.h @@ -2,220 +2,55 @@ #include "CoreMinimal.h" #include "CommonButtonBase.h" -#include "Layout/Margin.h" -#include "Types/SlateEnums.h" -#include "UI/UIStyleTypes.h" -#include "UI/UIStyleTokens.h" #include "UIButton_Base.generated.h" -class UBorder; -class UTextBlock; -class UImage; class USizeBox; -class UScaleBox; +class UImage; +class UCanvasPanel; class UCommonTextBlock; -class UCommonActionWidget; +class UTextBlock; -DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnUIButtonActivatedByTimeout); -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnUIButtonTimerUpdated, float, TimeRemaining); +struct FUIStyle; +struct FUIStyleButton; /** - * Botão base do ZMMO — porte 1:1 do UI_Button_Master do projeto Hyper para C++ - * auto-configurável, trocando o Struct_Style_Button do Hyper pela camada de - * tema C++ (FUIStyle via UZMMOThemeSubsystem::GetActiveUIStyle()). - * - * Fundação: CommonUI (UCommonButtonBase) cuida de input/foco/click. - * Camada Abstract (padrão "_Abstract" do Hyper). WBP UI_Button_Base herda - * disto; UI_Button_Master herda do WBP. Os widgets visuais são opcionais - * (BindWidgetOptional) e nomeados como no Hyper. - * - * Auto-config: NativePreConstruct chama InitializeButton (text/number/icon/ - * sizebox/estilo) + ApplyInputActionStyle. Reage à troca de tema. + * Botão base do ZMMO (CommonUI). Hoje expõe BindWidgetOptional dos widgets + * que o WBP UI_Button_Master_New consome, e helpers pra ler o estilo ativo + * de DT_UI_Styles. A aplicação visual (pintar brushes/cores/fonte) entra + * depois — esta camada só prepara o acesso. */ UCLASS(Abstract, Blueprintable) class ZMMO_API UUIButton_Base : public UCommonButtonBase { GENERATED_BODY() -public: - // ---- Botão ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button") - EUIButtonShape ButtonTypeSelection = EUIButtonShape::Rectangle; - - /** - * Variante visual do botão (dropdown vem de FUIStyle.Button.Backgrounds/ - * Strokes/Fonts no DT_UI_Styles + as 4 clássicas como fallback). - * Data-driven via FName, sem enum fixo (padrão Hyper-style). - */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button", - meta = (GetOptions = "GetVariantOptions")) - FName Variant = TEXT("Primary"); - - /** Opções do dropdown de Variant (data-driven do DT_UI_Styles). */ - UFUNCTION() - TArray GetVariantOptions() const; - - /** Hyper "Transform Policy = To Upper": força o texto em maiúsculas. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button") - bool bUppercaseText = true; - - // ---- Text Style ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Style") - FText ButtonTextValue = FText::FromString(TEXT("Button Text")); - - /** Alinhamento do texto dentro do botão (esquerda/centro/direita). */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Style") - TEnumAsByte TextAlign = ETextJustify::Center; - - /** true = texto escala p/ caber no tamanho do botão (ScaleBox ScaleToFit); - * false = usa o tamanho fixo da fonte da variante. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Text Style") - bool bAutoSizeText = true; - - /** Arredonda o Background (RoundedBox) e desenha a borda na cor da - * variante. Desligado = caixa reta. Raio/largura vêm de FUIStyleButton. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Button") - bool bRoundedBackground = true; - - // ---- Number Text ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Number Text") - bool bShowNumberText = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Number Text") - int32 NumberTextAmount = 0; - - // ---- Icon ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Icon") - bool bUseIconInsteadOfText = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Icon") - TObjectPtr IconImage = nullptr; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Icon") - EUIIconType IconTypeSelection = EUIIconType::None; - - // ---- Size ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Size") - float InHeightOverride = 50.f; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Size") - float InWidthOverride = 150.f; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Size") - bool bDoNotOverrideWithSizebox = false; - - // ---- Input Action Style ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Action Style") - bool bShowInputActionWidget = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Action Style") - FMargin InputPadding = FMargin(0.f, 0.f, 0.f, -22.f); - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Action Style") - TEnumAsByte InputHorzAlignment = HAlign_Center; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Input Action Style") - TEnumAsByte InputVertAlignment = VAlign_Bottom; - - // ---- Deactivate by Timer ---- - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deactivate By Timer") - bool bDeactivatedOnConstructWithTimeout = false; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Deactivate By Timer") - float Timeout = 0.f; - - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Timer") - float TimeUpdateFrequency = 0.05f; - - UPROPERTY(BlueprintReadOnly, Category = "Timer") - float TimeRemaining = 0.f; - - UPROPERTY(BlueprintAssignable, Category = "Timer") - FOnUIButtonActivatedByTimeout OnButtonActivatedByTimeout; - - UPROPERTY(BlueprintAssignable, Category = "Timer") - FOnUIButtonTimerUpdated OnButtonTimerUpdated; - - // ---- API (porte 1:1 das funções do Hyper) ---- - UFUNCTION(BlueprintCallable, Category = "UI Button") - void SetButtonText(FText InText); - - UFUNCTION(BlueprintCallable, Category = "UI Button") - void SetNumberText(); - - UFUNCTION(BlueprintCallable, Category = "UI Button") - void SetIcon(); - - UFUNCTION(BlueprintCallable, Category = "UI Button") - void ApplySizeBox(); - - UFUNCTION(BlueprintCallable, Category = "UI Button") - void ApplyInputActionStyle(); - - /** Orquestrador (Hyper "Initialize Button"): aplica tudo + estilo do tema. */ - UFUNCTION(BlueprintCallable, Category = "UI Button") - void InitializeButton(); - - /** Re-resolve os tokens do tema ativo e reaplica (Hyper "Update Button Style"). */ - UFUNCTION(BlueprintCallable, Category = "UI Style") - void RefreshUIStyle(); - - /** Estado visual do botão (mapeia nos tokens BgNormal/Hover/Pressed/Disabled). */ - enum class EUIButtonVisual : uint8 { Normal, Hovered, Pressed, Disabled }; - - /** Pinta o Background (fill + borda) conforme o estado, re-resolvendo o tema. */ - void ApplyVisualState(EUIButtonVisual State); - protected: - virtual void NativePreConstruct() override; - virtual void NativeConstruct() override; - virtual void NativeDestruct() override; + // ---- Widgets BindWidgetOptional (espelham a árvore do UI_Button_Master_New) ---- + UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional)) + TObjectPtr SizeBox; - // Estados do UCommonButtonBase → repinta o Background pela variante. - virtual void NativeOnHovered() override; - virtual void NativeOnUnhovered() override; - virtual void NativeOnPressed() override; - virtual void NativeOnReleased() override; - virtual void NativeOnEnabled() override; - virtual void NativeOnDisabled() override; + UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional)) + TObjectPtr ImgStoke; - /** Hook opcional: o WBP pode estender/sobrescrever a aplicação visual. */ - UFUNCTION(BlueprintImplementableEvent, Category = "UI Style", - meta = (DisplayName = "Apply UI Style")) - void BP_ApplyUIStyle(const FUIStyleButton& Button, const FUIStyleButtonVariant& VariantStyle); + UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional)) + TObjectPtr CanvasPanel_Text; - FUIStyleButtonVariant ResolveVariant(const FUIStyleButton& Button) const; - - // ---- Widgets visuais opcionais (nomes espelham o Hyper) ---- - UPROPERTY(meta = (BindWidgetOptional)) - TObjectPtr SizeBox_Master; - - UPROPERTY(meta = (BindWidgetOptional)) + UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional)) TObjectPtr ButtonText; - /** Envolve o ButtonText: escala o texto p/ caber no botão (bAutoSizeText). */ - UPROPERTY(meta = (BindWidgetOptional)) - TObjectPtr TextScaleBox; - - UPROPERTY(meta = (BindWidgetOptional)) + UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional)) TObjectPtr Number_Text; - UPROPERTY(meta = (BindWidgetOptional)) - TObjectPtr Image_Icon; + UPROPERTY(BlueprintReadOnly, Category = "UI Button", meta = (BindWidgetOptional)) + TObjectPtr ImgIcon; - /** Fundo temável (nossa adição sobre o Hyper, p/ FUIStyle). */ - UPROPERTY(meta = (BindWidgetOptional)) - TObjectPtr Background; + // ---- Acesso ao estilo ativo (DT_UI_Styles) — C++ only ---- -private: - void StartDeactivateTimeout(); - void HandleTimeoutFinished(); - void HandleTimerTick(); + /** Carrega DT_UI_Styles e devolve o FUIStyle da row pedida (default "Default"). + * Retorna nullptr se a DT ou a row não existirem. Ponteiro válido enquanto + * a DT estiver carregada — uso típico é leitura imediata, sem armazenar. */ + const FUIStyle* GetActiveUIStyle(FName ThemeId = TEXT("Default")) const; - UFUNCTION() - void HandleThemeChanged(FName NewThemeId); - - bool bThemeBound = false; - FTimerHandle InactivityTimer; - FTimerHandle TimerTickHandle; + /** Atalho: devolve só o bloco Button do FUIStyle ativo. */ + const FUIStyleButton* GetActiveButtonStyle(FName ThemeId = TEXT("Default")) const; }; diff --git a/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.cpp b/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.cpp index 7ec2f4f..e840523 100644 --- a/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.cpp +++ b/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.cpp @@ -52,83 +52,43 @@ void UUIPanel_Base::RefreshUIStyle() const FUIStyle AS = ResolvePanelStyle(this, Fallback); const FUIStylePanel& P = AS.Panel; - // ---- Modo TEXTURA (padrão Hyper): brush por EUIPanelTexture ---- - // Fiel ao UI_Panel_Master do Hyper: só faz SetBrush nos dois Borders - // (Find no mapa por chave). Sem padding/visibility — a arte da textura - // já traz a moldura; o conteúdo é injetado pelo WBP filho. - // Seed dos mapas da instância a partir do tema quando vazios — assim o - // Details mostra Panel Background/Outline preenchidos e editáveis (igual - // ao Hyper, cujo `Panels` é alimentado pelo estilo). Edições do designer - // têm prioridade; o tema (P) é fallback por chave. - if (Panels.PanelBackground.Num() == 0) { Panels.PanelBackground = P.PanelBackground; } - if (Panels.PanelOutline.Num() == 0) { Panels.PanelOutline = P.PanelOutline; } + // bUseTheme = true -> brushes vêm da DT (lookup pelas 3 chaves). + // bUseTheme = false -> brushes vêm dos 3 FSlateBrush em Panels (direto). - const FSlateBrush* BgTex = nullptr; - if (PanelTexture != EUIPanelTexture::None) + static const FSlateBrush NoDrawBrush = [] { - BgTex = Panels.PanelBackground.Find(PanelTexture); - if (!BgTex) { BgTex = P.PanelBackground.Find(PanelTexture); } - } - if (BgTex) + FSlateBrush B; + B.DrawAs = ESlateBrushDrawType::NoDrawType; + return B; + }(); + + auto ResolveFromTheme = [](EUIPanelTexture Key, + const TMap& Map) -> const FSlateBrush* { - Background->SetBrush(*BgTex); - if (Outline) - { - // Hyper: Find sempre seguido de SetBrush. No Hyper a entrada de - // outline ausente é um brush TRANSPARENTE (alpha 0) — não some - // widget, só não desenha. Um FSlateBrush default desenha um - // retângulo BRANCO; o equivalente correto é DrawAs=NoDrawType. - const FSlateBrush* OlTex = Panels.PanelOutline.Find(PanelTexture); - if (!OlTex) { OlTex = P.PanelOutline.Find(PanelTexture); } - static const FSlateBrush NoDrawBrush = [] - { - FSlateBrush B; - B.DrawAs = ESlateBrushDrawType::NoDrawType; - return B; - }(); - Outline->SetBrush(OlTex ? *OlTex : NoDrawBrush); - } - BP_ApplyPanelStyle(P); - return; - } + return (Key == EUIPanelTexture::None) ? nullptr : Map.Find(Key); + }; + + const FSlateBrush* BgTex = bUseTheme + ? ResolveFromTheme(BackgroundKey, P.PanelBackground) + : &Panels.PanelBackground; + Background->SetBrush(BgTex ? *BgTex : NoDrawBrush); - // ---- Modo COR (RoundedBox) ---- if (Outline) { - Outline->SetVisibility(ESlateVisibility::Collapsed); + const FSlateBrush* OlTex = bUseTheme + ? ResolveFromTheme(OutlineKey, P.PanelOutline) + : &Panels.PanelOutline; + Outline->SetBrush(OlTex ? *OlTex : NoDrawBrush); } - FLinearColor Fill; - FLinearColor OutlineColor = P.BorderColor; - switch (PanelType) + if (OutlineEffect) { - case EUIPanelType::Secondary: Fill = P.BgRaised; break; - case EUIPanelType::Tertiary: Fill = P.BgSunken; break; - case EUIPanelType::Card: Fill = P.CardSelectedBg; OutlineColor = P.CardSelectedBorder; break; - case EUIPanelType::Primary: - case EUIPanelType::None: - default: Fill = P.Bg; break; + const FSlateBrush* OeTex = bUseTheme + ? ResolveFromTheme(OutlineEffectKey, P.PanelOutlineEffect) + : &Panels.PanelOutlineEffect; + OutlineEffect->SetBrush(OeTex ? *OeTex : NoDrawBrush); } - 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(OutlineColor), P.BorderWidth); - Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius; - } - else - { - Brush.DrawAs = ESlateBrushDrawType::Box; - Brush.OutlineSettings = FSlateBrushOutlineSettings( - FVector4(0, 0, 0, 0), FSlateColor(OutlineColor), P.BorderWidth); - } - Background->SetBrush(Brush); - Background->SetPadding(bUseSmallPadding ? P.PaddingSmall : P.Padding); - BP_ApplyPanelStyle(P); } diff --git a/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.h b/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.h index 843cdca..764218e 100644 --- a/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.h +++ b/Source/ZMMO/Game/UI/Widgets/UIPanel_Base.h @@ -23,34 +23,31 @@ 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; - /** - * Conjunto de textura (modo Hyper). Se != None E houver brush no mapa - * FUIStylePanel.PanelBackground p/ esta chave, usa o painel TEXTURIZADO - * (brush bg + outline). Senão, cai no modo COR (RoundedBox acima). + * true = lê brushes da DT_UI_Styles (FUIStylePanel) — tema centralizado. + * false = ignora a DT e usa apenas `Panels` (brushes manuais no Details). */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel") - EUIPanelTexture PanelTexture = EUIPanelTexture::None; + bool bUseTheme = true; - /** - * Mapas de brush por instância — espelha o `Panels` do UI_Panel_Master - * do Hyper (Details mostra Panel Background / Panel Outline editáveis). - * Tem prioridade. Se não houver brush p/ a chave aqui, cai no tema - * (DT_UI_Styles). Em NativePreConstruct é semeado a partir do tema - * quando vazio, então por padrão o tema manda — como no Hyper. - */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel") + // ---- Modo TEMA: escolhe a chave do mapa FUIStylePanel pra cada Border. ---- + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel", + meta = (EditCondition = "bUseTheme", EditConditionHides)) + EUIPanelTexture BackgroundKey = EUIPanelTexture::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel", + meta = (EditCondition = "bUseTheme", EditConditionHides)) + EUIPanelTexture OutlineKey = EUIPanelTexture::None; + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel", + meta = (EditCondition = "bUseTheme", EditConditionHides)) + EUIPanelTexture OutlineEffectKey = EUIPanelTexture::None; + + // ---- Modo MANUAL: 3 brushes editáveis direto no Details. ---- + + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Panel", + meta = (EditCondition = "!bUseTheme", EditConditionHides)) FUIPanelBrushSet Panels; /** Re-resolve os tokens do tema ativo e reaplica no Background. */ @@ -75,6 +72,10 @@ protected: UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr Outline; + /** Efeito sobre o contorno (glow/embossing/etc.) — pintado acima do Outline. */ + UPROPERTY(meta = (BindWidgetOptional)) + TObjectPtr OutlineEffect; + private: UFUNCTION() void HandleThemeChanged(FName NewThemeId);