feat(ui): estados Hover/Pressed/Disabled no botao (ApplyVisualState + NativeOn*)

ApplyVisualState(estado) re-resolve o tema e pinta o Background (RoundedBox/Box) com fill+borda do estado: Normal=BgNormal/BorderNormal, Hovered=BgHover/BorderHover, Pressed=BgPressed/BorderHover, Disabled=BgDisabled/BorderNormal. Overrides do UCommonButtonBase: NativeOnHovered/Unhovered/Pressed/Released(volta p/ Hovered se IsHovered senao Normal)/Enabled/Disabled. RefreshUIStyle agora chama ApplyVisualState(Normal). Compila OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-19 00:01:18 -03:00
parent 2da2bc7101
commit 69fe754e34
2 changed files with 91 additions and 26 deletions

View File

@@ -166,32 +166,9 @@ void UUIButton_Base::RefreshUIStyle()
const FUIStyle& ActiveStyle = ResolveActiveStyle(this, Fallback);
const FUIStyleButtonVariant& VariantStyle = ResolveVariant(ActiveStyle.Button);
if (Background)
{
// Fundo + borda na cor da variante. RoundedBox dá cantos arredondados
// e a borda colorida (BorderNormal) — "só borda" = BgNormal transparente.
FSlateBrush Brush = Background->Background;
Brush.TintColor = FSlateColor(VariantStyle.BgNormal);
if (bRoundedBackground)
{
const float R = ActiveStyle.Button.CornerRadius;
Brush.DrawAs = ESlateBrushDrawType::RoundedBox;
Brush.OutlineSettings = FSlateBrushOutlineSettings(
FVector4(R, R, R, R),
FSlateColor(VariantStyle.BorderNormal),
ActiveStyle.Button.BorderWidth);
Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius;
}
else
{
Brush.DrawAs = ESlateBrushDrawType::Box;
Brush.OutlineSettings = FSlateBrushOutlineSettings(
FVector4(0, 0, 0, 0),
FSlateColor(VariantStyle.BorderNormal),
ActiveStyle.Button.BorderWidth);
}
Background->SetBrush(Brush);
}
// Fundo + borda no estado Normal (hover/pressed/disabled via NativeOn*).
ApplyVisualState(EUIButtonVisual::Normal);
if (ButtonText)
{
// Tipografia: CommonTextStyle da variante (padrão Hyper/CommonUI).
@@ -229,6 +206,80 @@ void UUIButton_Base::RefreshUIStyle()
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)
{
const float R = AS.Button.CornerRadius;
Brush.DrawAs = ESlateBrushDrawType::RoundedBox;
Brush.OutlineSettings = FSlateBrushOutlineSettings(
FVector4(R, R, R, R), FSlateColor(Outline), AS.Button.BorderWidth);
Brush.OutlineSettings.RoundingType = ESlateBrushRoundingType::FixedRadius;
}
else
{
Brush.DrawAs = ESlateBrushDrawType::Box;
Brush.OutlineSettings = FSlateBrushOutlineSettings(
FVector4(0, 0, 0, 0), FSlateColor(Outline), AS.Button.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();

View File

@@ -150,11 +150,25 @@ public:
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;
// 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;
/** Hook opcional: o WBP pode estender/sobrescrever a aplicação visual. */
UFUNCTION(BlueprintImplementableEvent, Category = "UI Style",
meta = (DisplayName = "Apply UI Style"))