setup equipment ui

This commit is contained in:
2026-05-27 16:20:10 +03:00
parent 9792ede1e8
commit 5c1ca57a04
134 changed files with 464 additions and 354 deletions
@@ -205,7 +205,7 @@ UClothingItemInstance* UClothingManager::RemoveClothing(const EClothingSlotType
void UClothingManager::DropClothing(const EClothingSlotType ClothingType)
{
const UClothingItemInstance* ClothingItemInstance = RemoveClothing(ClothingType);
UClothingItemInstance* ClothingItemInstance = RemoveClothing(ClothingType);
if (!ClothingItemInstance)
return;
@@ -12,7 +12,7 @@ class UGlobalSaveGameData;
class AClothingPickup;
class UClothingItemInstance;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnClothingChangeSignature, const UClothingItemInstance*, ClothingItemInstance);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnClothingChangeSignature, UClothingItemInstance*, ClothingItemInstance);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class NAKEDDESIRE_API UClothingManager : public UActorComponent
@@ -11,6 +11,9 @@ class NAKEDDESIRE_API ANakedDesireHUD : public AHUD
{
GENERATED_BODY()
public:
UGameLayoutWidget* GetGameLayout() const { return GameLayoutWidget; }
protected:
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<UGameLayoutWidget> GameLayoutWidgetClass;
@@ -63,7 +63,7 @@ FText UEquipClothingRestriction::GetDescription() const
});
}
void UEquipClothingRestriction::OnClothingEquipped(const UClothingItemInstance* ClothingItemInstance)
void UEquipClothingRestriction::OnClothingEquipped(UClothingItemInstance* ClothingItemInstance)
{
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingItemInstance](const UClothingItem* Item)
{
@@ -75,7 +75,7 @@ void UEquipClothingRestriction::OnClothingEquipped(const UClothingItemInstance*
}
}
void UEquipClothingRestriction::OnClothingUnequipped(const UClothingItemInstance* ClothingItemInstance)
void UEquipClothingRestriction::OnClothingUnequipped(UClothingItemInstance* ClothingItemInstance)
{
const bool IsTargetClothing = ClothingItems.FindByPredicate([&ClothingItemInstance](const UClothingItem* Item)
{
@@ -28,10 +28,10 @@ private:
FDelegateHandle ClothingUnequippedDelegateHandle;
UFUNCTION()
void OnClothingEquipped(const UClothingItemInstance* ClothingItemInstance);
void OnClothingEquipped(UClothingItemInstance* ClothingItemInstance);
UFUNCTION()
void OnClothingUnequipped(const UClothingItemInstance* ClothingItemInstance);
void OnClothingUnequipped(UClothingItemInstance* ClothingItemInstance);
void CheckClothing();
};
@@ -56,7 +56,7 @@ FText UExposeBodyPartRestriction::GetDescription() const
});
}
void UExposeBodyPartRestriction::EquipClothing(const UClothingItemInstance* ClothingItemInstance)
void UExposeBodyPartRestriction::EquipClothing(UClothingItemInstance* ClothingItemInstance)
{
if (IsSuccess) // TODO: Add covered body part resolution
{
@@ -64,7 +64,7 @@ void UExposeBodyPartRestriction::EquipClothing(const UClothingItemInstance* Clot
}
}
void UExposeBodyPartRestriction::UnequipClothing(const UClothingItemInstance* ClothingItemInstance)
void UExposeBodyPartRestriction::UnequipClothing(UClothingItemInstance* ClothingItemInstance)
{
if (IsSuccess)
return;
@@ -20,17 +20,17 @@ class NAKEDDESIRE_API UExposeBodyPartRestriction : public UGoalRestriction
UPROPERTY(EditDefaultsOnly)
EBodyPart BodyPart;
protected:
public:
virtual void Init(ANakedDesireCharacter* PlayerCharacter) override;
virtual void Stop() override;
virtual FText GetDescription() const override;
private:
UFUNCTION()
void EquipClothing(const UClothingItemInstance* ClothingItemInstance);
void EquipClothing(UClothingItemInstance* ClothingItemInstance);
UFUNCTION()
void UnequipClothing(const UClothingItemInstance* ClothingItemInstance);
void UnequipClothing(UClothingItemInstance* ClothingItemInstance);
void CheckClothing();
};
@@ -17,7 +17,9 @@
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingSlotsData.h"
#include "NakedDesire/Global/Constants.h"
#include "NakedDesire/Global/NakedDesireHUD.h"
#include "NakedDesire/Global/NakedDesireUserSettings.h"
#include "NakedDesire/UI/GameLayoutWidget.h"
#include "NakedDesire/UI/RadialMenu/RadialMenuController.h"
#include "Perception/AIPerceptionStimuliSourceComponent.h"
#include "Perception/AISense_Sight.h"
@@ -166,6 +168,8 @@ void ANakedDesireCharacter::BeginPlay()
ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingEquip);
ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &ANakedDesireCharacter::OnClothingUnequip);
HUD = Cast<ANakedDesireHUD>(UGameplayStatics::GetPlayerController(GetWorld(), 0)->GetHUD());
UNakedDesireUserSettings::GetNakedDesireUserSettings()->OnSettingsChanged.AddUniqueDynamic(this, &ANakedDesireCharacter::OnSettingsChanged);
}
@@ -258,7 +262,7 @@ void ANakedDesireCharacter::OnEndOverlap(UPrimitiveComponent* OverlappedComponen
}
}
void ANakedDesireCharacter::OnClothingEquip(const UClothingItemInstance* ClothingItemInstance)
void ANakedDesireCharacter::OnClothingEquip(UClothingItemInstance* ClothingItemInstance)
{
if (ClothingItemInstance->GetClothingItem()->HiddenBodyParts.Contains(EBodyPart::Ass))
{
@@ -275,7 +279,7 @@ void ANakedDesireCharacter::OnClothingEquip(const UClothingItemInstance* Clothin
}
}
void ANakedDesireCharacter::OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance)
void ANakedDesireCharacter::OnClothingUnequip(UClothingItemInstance* ClothingItemInstance)
{
if (!UNakedDesireUserSettings::GetNakedDesireUserSettings()->GetIsCensorshipEnabled() && !IS_DEMO)
return;
@@ -366,8 +370,7 @@ void ANakedDesireCharacter::OnCrouchToggle(const FInputActionValue& Value)
void ANakedDesireCharacter::OnEquipmentPress(const FInputActionValue& Value)
{
BuildRadialMenuEntries();
RadialMenuController->OpenMenu();
HUD->GetGameLayout()->OpenInventory();
}
void ANakedDesireCharacter::BuildRadialMenuEntries()
@@ -13,6 +13,8 @@
#include "Perception/AISightTargetInterface.h"
#include "NakedDesireCharacter.generated.h"
class ANakedDesireHUD;
class UClothingItemInstance;
class UClothingSlotsData;
class URadialMenuController;
class UAIPerceptionStimuliSourceComponent;
@@ -187,10 +189,10 @@ private:
int32 OtherBodyIndex);
UFUNCTION()
void OnClothingEquip(const UClothingItemInstance* ClothingItemInstance);
void OnClothingEquip(UClothingItemInstance* ClothingItemInstance);
UFUNCTION()
void OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance);
void OnClothingUnequip(UClothingItemInstance* ClothingItemInstance);
UFUNCTION()
void OnSettingsChanged(UNakedDesireUserSettings* Settings);
@@ -205,4 +207,7 @@ private:
void BuildRadialMenuEntries();
bool CheckSight(const FVector& StartLocation, const FVector& EndLocation, FHitResult& HitResult, const AActor* IgnoreActor);
UPROPERTY()
TObjectPtr<ANakedDesireHUD> HUD;
};
@@ -60,12 +60,12 @@ void APlayerCinematic::BeginPlay()
}
}
void APlayerCinematic::OnClothingEquip(const UClothingItemInstance* ClothingItemInstance)
void APlayerCinematic::OnClothingEquip(UClothingItemInstance* ClothingItemInstance)
{
EquipClothing(ClothingItemInstance);
}
void APlayerCinematic::OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance)
void APlayerCinematic::OnClothingUnequip(UClothingItemInstance* ClothingItemInstance)
{
UnequipClothing(ClothingItemInstance);
}
+3 -4
View File
@@ -60,16 +60,15 @@ class NAKEDDESIRE_API APlayerCinematic : public ACharacter
public:
APlayerCinematic();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnClothingEquip(const UClothingItemInstance* ClothingItemInstance);
void OnClothingEquip(UClothingItemInstance* ClothingItemInstance);
UFUNCTION()
void OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance);
void OnClothingUnequip(UClothingItemInstance* ClothingItemInstance);
USkeletalMeshComponent* GetMeshByType(const EClothingSlotType SlotType) const;
void EquipClothing(const UClothingItemInstance* ClothingItemInstance);
+2 -2
View File
@@ -46,12 +46,12 @@ APlayerImpostor::APlayerImpostor()
ShoesMeshComponent->SetupAttachment(GetMesh());
}
void APlayerImpostor::OnClothingEquip(const UClothingItemInstance* ClothingItemInstance)
void APlayerImpostor::OnClothingEquip(UClothingItemInstance* ClothingItemInstance)
{
EquipClothing(ClothingItemInstance);
}
void APlayerImpostor::OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance)
void APlayerImpostor::OnClothingUnequip(UClothingItemInstance* ClothingItemInstance)
{
UnequipClothing(ClothingItemInstance);
}
+2 -2
View File
@@ -71,10 +71,10 @@ public:
private:
UFUNCTION()
void OnClothingEquip(const UClothingItemInstance* ClothingItemInstance);
void OnClothingEquip(UClothingItemInstance* ClothingItemInstance);
UFUNCTION()
void OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance);
void OnClothingUnequip(UClothingItemInstance* ClothingItemInstance);
USkeletalMeshComponent* GetMesh() const { return Mesh; };
USkeletalMeshComponent* GetMeshByType(const EClothingSlotType SlotType) const;
@@ -1 +1,8 @@
#include "GameLayoutWidget.h"
#include "Widgets/CommonActivatableWidgetContainer.h"
#include "Inventory/InventoryScreenWidget.h"
void UGameLayoutWidget::OpenInventory()
{
InventoryScreenWidget = WidgetStack->AddWidget<UInventoryScreenWidget>(InventoryScreenWidgetClass);
}
+10
View File
@@ -4,6 +4,7 @@
#include "CommonUserWidget.h"
#include "GameLayoutWidget.generated.h"
class UInventoryScreenWidget;
class UHUDWidget;
class UCommonActivatableWidgetStack;
@@ -17,4 +18,13 @@ class NAKEDDESIRE_API UGameLayoutWidget : public UCommonUserWidget
UPROPERTY(meta = (BindWidget))
TObjectPtr<UHUDWidget> HUD;
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<UInventoryScreenWidget> InventoryScreenWidgetClass;
UPROPERTY()
TObjectPtr<UInventoryScreenWidget> InventoryScreenWidget;
public:
void OpenInventory();
};
@@ -2,3 +2,63 @@
#include "EquipmentPanelWidget.h"
#include "EquipmentSlotWidget.h"
void UEquipmentPanelWidget::NativeConstruct()
{
Super::NativeConstruct();
InitSlotTypes();
const TArray<UEquipmentSlotWidget*> AllSlots = {
NipplesSlot, AnalSlot, VaginaSlot,
HeadSlot, NeckSlot, FaceSlot, EyesSlot,
BodysuitSlot, TopSlot, BottomSlot,
UnderwearTopSlot, UnderwearBottomSlot,
SocksSlot, FootwearSlot, OuterwearSlot,
WristRestraintSlot, AnkleRestraintSlot, NeckRestraintSlot
};
for (UEquipmentSlotWidget* Slot : AllSlots)
{
if (Slot)
{
Slot->OnEquipmentSlotClicked.BindUObject(this, &UEquipmentPanelWidget::HandleSlotClicked);
}
}
}
void UEquipmentPanelWidget::NativePreConstruct()
{
Super::NativePreConstruct();
InitSlotTypes();
}
void UEquipmentPanelWidget::HandleSlotClicked(UEquipmentSlotWidget* SlotWidget)
{
OnSlotClicked.ExecuteIfBound(SlotWidget);
}
void UEquipmentPanelWidget::InitSlotTypes()
{
if (NipplesSlot) NipplesSlot->SetSlotType(EClothingSlotType::Nipples);
if (AnalSlot) AnalSlot->SetSlotType(EClothingSlotType::Anal);
if (VaginaSlot) VaginaSlot->SetSlotType(EClothingSlotType::Vagina);
if (HeadSlot) HeadSlot->SetSlotType(EClothingSlotType::Head);
if (NeckSlot) NeckSlot->SetSlotType(EClothingSlotType::Neck);
if (FaceSlot) FaceSlot->SetSlotType(EClothingSlotType::Face);
if (EyesSlot) EyesSlot->SetSlotType(EClothingSlotType::Eyes);
if (BodysuitSlot) BodysuitSlot->SetSlotType(EClothingSlotType::Bodysuit);
if (TopSlot) TopSlot->SetSlotType(EClothingSlotType::Top);
if (BottomSlot) BottomSlot->SetSlotType(EClothingSlotType::Bottom);
if (UnderwearTopSlot) UnderwearTopSlot->SetSlotType(EClothingSlotType::UnderwearTop);
if (UnderwearBottomSlot) UnderwearBottomSlot->SetSlotType(EClothingSlotType::UnderwearBottom);
if (SocksSlot) SocksSlot->SetSlotType(EClothingSlotType::Socks);
if (FootwearSlot) FootwearSlot->SetSlotType(EClothingSlotType::Footwear);
if (OuterwearSlot) OuterwearSlot->SetSlotType(EClothingSlotType::Outerwear);
if (WristRestraintSlot) WristRestraintSlot->SetSlotType(EClothingSlotType::WristRestraint);
if (AnkleRestraintSlot) AnkleRestraintSlot->SetSlotType(EClothingSlotType::AnkleRestraint);
if (NeckRestraintSlot) NeckRestraintSlot->SetSlotType(EClothingSlotType::NeckRestraint);
}
@@ -6,11 +6,76 @@
#include "CommonUserWidget.h"
#include "EquipmentPanelWidget.generated.h"
/**
*
*/
UCLASS()
class UEquipmentSlotWidget;
UCLASS(Abstract)
class NAKEDDESIRE_API UEquipmentPanelWidget : public UCommonUserWidget
{
GENERATED_BODY()
};
public:
DECLARE_DELEGATE_OneParam(FOnSlotClicked, UEquipmentSlotWidget*);
FOnSlotClicked OnSlotClicked;
protected:
virtual void NativeConstruct() override;
virtual void NativePreConstruct() override;
private:
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> NipplesSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> AnalSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> VaginaSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> HeadSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> NeckSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> FaceSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> EyesSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> BodysuitSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> TopSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> BottomSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> UnderwearTopSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> UnderwearBottomSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> SocksSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> FootwearSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> OuterwearSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> WristRestraintSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> AnkleRestraintSlot;
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UEquipmentSlotWidget> NeckRestraintSlot;
void HandleSlotClicked(UEquipmentSlotWidget* SlotWidget);
void InitSlotTypes();
};
@@ -0,0 +1,29 @@
// © 2025 Naked People Team. All Rights Reserved.
#include "EquipmentSlotMenuWidget.h"
#include "Components/Button.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void UEquipmentSlotMenuWidget::Init(const EClothingSlotType InSlotType)
{
SlotType = InSlotType;
}
void UEquipmentSlotMenuWidget::NativeConstruct()
{
Super::NativeConstruct();
Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
DropClothingBtn->OnClicked.AddUniqueDynamic(this, &UEquipmentSlotMenuWidget::OnDropClothingClicked);
}
void UEquipmentSlotMenuWidget::OnDropClothingClicked()
{
Player->ClothingManager->DropClothing(SlotType);
OnActionPerformed.Broadcast();
}
@@ -0,0 +1,41 @@
// © 2025 Naked People Team. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "CommonUserWidget.h"
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "EquipmentSlotMenuWidget.generated.h"
class ANakedDesireCharacter;
class UButton;
UCLASS(Abstract)
class NAKEDDESIRE_API UEquipmentSlotMenuWidget : public UCommonUserWidget
{
GENERATED_BODY()
public:
void Init(EClothingSlotType InSlotType);
EClothingSlotType GetSlotType() const { return SlotType; }
DECLARE_MULTICAST_DELEGATE(FOnActionPerformed);
FOnActionPerformed OnActionPerformed;
protected:
virtual void NativeConstruct() override;
private:
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> DropClothingBtn;
UPROPERTY()
TObjectPtr<ANakedDesireCharacter> Player;
UPROPERTY()
EClothingSlotType SlotType;
UFUNCTION()
void OnDropClothingClicked();
};
@@ -2,34 +2,88 @@
#include "EquipmentSlotWidget.h"
#include "Kismet/GameplayStatics.h"
#include "NakedDesire/Clothing/ClothingItem.h"
#include "NakedDesire/Clothing/ClothingItemInstance.h"
#include "NakedDesire/Clothing/ClothingManager.h"
#include "NakedDesire/Clothing/ClothingSlotsData.h"
#include "NakedDesire/Player/NakedDesireCharacter.h"
void UEquipmentSlotWidget::SetItem(UClothingItemInstance* InItem)
{
ClothingItemInstance = InItem;
IconImage->SetBrushFromTexture(InItem->GetClothingItem()->Icon);
IconImage->SetVisibility(ESlateVisibility::SelfHitTestInvisible);
SetIsEnabled(true);
}
void UEquipmentSlotWidget::ClearItem()
{
ClothingItemInstance = nullptr;
IconImage->SetBrushFromTexture(nullptr);
IconImage->SetVisibility(ESlateVisibility::Hidden);
SetIsEnabled(false);
}
void UEquipmentSlotWidget::NativeOnClicked()
{
Super::NativeOnClicked();
OnEquipmentSlotClicked.ExecuteIfBound(this);
}
void UEquipmentSlotWidget::NativePreConstruct()
{
Super::NativePreConstruct();
// if (!ClothingSlotsData->Slots.Contains(SlotType))
// return;
// FClothingSlotData& SlotData = ClothingSlotsData->Slots[SlotType];
// PlaceholderImage->SetBrushFromTexture(&SlotData.Icon);
InitSlotVisuals();
}
void UEquipmentSlotWidget::OnClothingEquip(UClothingItemInstance* InClothingItemInstance)
{
if (InClothingItemInstance->GetClothingItem()->SlotType != SlotType)
return;
SetItem(InClothingItemInstance);
}
void UEquipmentSlotWidget::OnClothingUnequip(UClothingItemInstance* InClothingItemInstance)
{
if (InClothingItemInstance->GetClothingItem()->SlotType != SlotType)
return;
ClearItem();
}
void UEquipmentSlotWidget::InitSlotVisuals()
{
if (!ClothingSlotsData)
return;
const FClothingSlotData& SlotData = ClothingSlotsData->Slots[SlotType];
PlaceholderImage->SetBrushFromTexture(SlotData.Icon);
}
void UEquipmentSlotWidget::SetSlotType(const EClothingSlotType InSlotType)
{
SlotType = InSlotType;
InitSlotVisuals();
}
void UEquipmentSlotWidget::NativeConstruct()
{
Super::NativeConstruct();
const ANakedDesireCharacter* Player = Cast<ANakedDesireCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
Player->ClothingManager->OnClothingEquip.AddUniqueDynamic(this, &UEquipmentSlotWidget::OnClothingEquip);
Player->ClothingManager->OnClothingUnequip.AddUniqueDynamic(this, &UEquipmentSlotWidget::OnClothingUnequip);
if (UClothingItemInstance* Item = Player->ClothingManager->GetSlotClothing(SlotType))
SetItem(Item);
else
ClearItem();
}
@@ -8,6 +8,8 @@
#include "NakedDesire/Clothing/ClothingSlotType.h"
#include "EquipmentSlotWidget.generated.h"
class UEquipmentSlotMenuWidget;
class ANakedDesireCharacter;
class UClothingSlotsData;
class UClothingItemInstance;
@@ -19,6 +21,14 @@ class NAKEDDESIRE_API UEquipmentSlotWidget : public UCommonButtonBase
public:
void SetItem(UClothingItemInstance* InItem);
void ClearItem();
EClothingSlotType GetSlotType() const { return SlotType; }
void SetSlotType(EClothingSlotType InSlotType);
virtual void NativeConstruct() override;
DECLARE_DELEGATE_OneParam(FOnEquipmentSlotClicked, UEquipmentSlotWidget* EquipmentSLotWidget)
FOnEquipmentSlotClicked OnEquipmentSlotClicked;
protected:
virtual void NativeOnClicked() override;
@@ -39,4 +49,12 @@ private:
UPROPERTY()
EClothingSlotType SlotType = EClothingSlotType::Anal;
UFUNCTION()
void OnClothingEquip(UClothingItemInstance* InClothingItemInstance);
UFUNCTION()
void OnClothingUnequip(UClothingItemInstance* InClothingItemInstance);
void InitSlotVisuals();
};
@@ -9,7 +9,7 @@
/**
*
*/
UCLASS()
UCLASS(Abstract)
class NAKEDDESIRE_API UInventoryPanelWidget : public UCommonUserWidget
{
GENERATED_BODY()
@@ -1 +1,87 @@
#include "InventoryScreenWidget.h"
#include "Components/Button.h"
#include "Components/CanvasPanel.h"
#include "Components/CanvasPanelSlot.h"
#include "EquipmentPanelWidget.h"
#include "EquipmentSlotMenuWidget.h"
#include "EquipmentSlotWidget.h"
void UInventoryScreenWidget::NativeOnActivated()
{
Super::NativeOnActivated();
if (!EquipmentSlotMenuWidget && EquipmentSlotMenuWidgetClass)
{
// Place the dynamic menu in the same canvas that hosts the blocker.
// The blocker must live in a UCanvasPanel that spans the area where
// outside clicks should be captured (typically the screen root canvas).
if (UCanvasPanel* MenuCanvas = Cast<UCanvasPanel>(MenuBlocker->GetParent()))
{
EquipmentSlotMenuWidget = CreateWidget<UEquipmentSlotMenuWidget>(this, EquipmentSlotMenuWidgetClass);
if (UCanvasPanelSlot* CanvasSlot = Cast<UCanvasPanelSlot>(MenuCanvas->AddChild(EquipmentSlotMenuWidget)))
{
CanvasSlot->SetAutoSize(true);
CanvasSlot->SetAnchors(FAnchors(0.f, 0.f));
// Render above the blocker so menu clicks aren't eaten by it.
CanvasSlot->SetZOrder(1);
}
EquipmentSlotMenuWidget->OnActionPerformed.AddUObject(this, &UInventoryScreenWidget::CloseMenu);
}
EquipmentPanelWidget->OnSlotClicked.BindUObject(this, &UInventoryScreenWidget::HandleSlotClicked);
MenuBlocker->OnClicked.AddUniqueDynamic(this, &UInventoryScreenWidget::CloseMenu);
}
CloseMenu();
}
void UInventoryScreenWidget::NativeOnDeactivated()
{
Super::NativeOnDeactivated();
CloseMenu();
}
void UInventoryScreenWidget::HandleSlotClicked(UEquipmentSlotWidget* SlotWidget)
{
if (!EquipmentSlotMenuWidget || !SlotWidget)
{
return;
}
const bool bMenuOpen = EquipmentSlotMenuWidget->GetVisibility() != ESlateVisibility::Collapsed;
if (bMenuOpen && EquipmentSlotMenuWidget->GetSlotType() == SlotWidget->GetSlotType())
{
CloseMenu();
return;
}
EquipmentSlotMenuWidget->Init(SlotWidget->GetSlotType());
if (UCanvasPanelSlot* MenuSlot = Cast<UCanvasPanelSlot>(EquipmentSlotMenuWidget->Slot))
{
if (UCanvasPanel* MenuCanvas = Cast<UCanvasPanel>(MenuBlocker->GetParent()))
{
const FGeometry& SlotGeom = SlotWidget->GetCachedGeometry();
const FVector2D AbsPos = SlotGeom.GetAbsolutePosition() + FVector2D(SlotGeom.GetAbsoluteSize().X, 0.f);
MenuSlot->SetPosition(MenuCanvas->GetCachedGeometry().AbsoluteToLocal(AbsPos));
}
}
MenuBlocker->SetVisibility(ESlateVisibility::Visible);
EquipmentSlotMenuWidget->SetVisibility(ESlateVisibility::Visible);
}
void UInventoryScreenWidget::CloseMenu()
{
if (EquipmentSlotMenuWidget)
{
EquipmentSlotMenuWidget->SetVisibility(ESlateVisibility::Collapsed);
}
if (MenuBlocker)
{
MenuBlocker->SetVisibility(ESlateVisibility::Collapsed);
}
}
@@ -4,8 +4,35 @@
#include "CommonActivatableWidget.h"
#include "InventoryScreenWidget.generated.h"
UCLASS()
class UButton;
class UEquipmentPanelWidget;
class UEquipmentSlotMenuWidget;
class UEquipmentSlotWidget;
UCLASS(Abstract)
class NAKEDDESIRE_API UInventoryScreenWidget : public UCommonActivatableWidget
{
GENERATED_BODY()
};
UPROPERTY(EditDefaultsOnly, Category = "UI")
TSubclassOf<UEquipmentSlotMenuWidget> EquipmentSlotMenuWidgetClass;
UPROPERTY()
TObjectPtr<UEquipmentSlotMenuWidget> EquipmentSlotMenuWidget;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UEquipmentPanelWidget> EquipmentPanelWidget;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> MenuBlocker;
protected:
virtual void NativeOnActivated() override;
virtual void NativeOnDeactivated() override;
private:
void HandleSlotClicked(UEquipmentSlotWidget* SlotWidget);
UFUNCTION()
void CloseMenu();
};