// Fill out your copyright notice in the Description page of Project Settings. #include "ItemDetailsWidget.h" #include "Components/Image.h" #include "Components/ProgressBar.h" #include "Components/TextBlock.h" #include "Components/Widget.h" #include "InventoryComponent.h" #include "ItemDataAsset.h" void UItemDetailsWidget::NativeConstruct() { Super::NativeConstruct(); // Etat vide des la construction : sans ca le panneau afficherait les valeurs // placeholder saisies dans la Designer jusqu'au premier survol. Clear(); } void UItemDetailsWidget::NativeDestruct() { BindInventory(nullptr); Super::NativeDestruct(); } void UItemDetailsWidget::BindInventory(UInventoryComponent* InInventory) { if (BoundInventory.Get() == InInventory) { return; } if (BoundInventory.IsValid()) { BoundInventory->OnInventoryChanged.RemoveDynamic(this, &UItemDetailsWidget::HandleInventoryChanged); } BoundInventory = InInventory; if (BoundInventory.IsValid()) { BoundInventory->OnInventoryChanged.AddDynamic(this, &UItemDetailsWidget::HandleInventoryChanged); } } void UItemDetailsWidget::ShowSlot(UInventoryComponent* InInventory, int32 InSlotIndex) { BindInventory(InInventory); SlotIndex = InSlotIndex; Refresh(); } void UItemDetailsWidget::Clear() { BindInventory(nullptr); SlotIndex = INDEX_NONE; Refresh(); } void UItemDetailsWidget::ClearSlot(const UInventoryComponent* InInventory, int32 InSlotIndex) { if (BoundInventory.Get() == InInventory && SlotIndex == InSlotIndex) { Clear(); } } void UItemDetailsWidget::HandleInventoryChanged() { // La case survolee a change sous le curseur : une charge consommee, une pile // deplacee. On relit plutot que de garder une copie perimee a l'ecran. Refresh(); } void UItemDetailsWidget::Refresh() { // Surtout pas "Slot" : UWidget a deja un membre de ce nom, et le masquer est // une erreur de compilation (C4458) traitee comme telle par le moteur. const FInventorySlot* HoveredSlot = nullptr; if (BoundInventory.IsValid()) { const TArray& Slots = BoundInventory->GetSlots(); if (Slots.IsValidIndex(SlotIndex) && !Slots[SlotIndex].IsEmpty()) { HoveredSlot = &Slots[SlotIndex]; } } if (ContentRoot) { // Hidden et non Collapsed : le panneau garde sa taille, donc rien ne // bouge dans la mise en page quand le curseur quitte une case. ContentRoot->SetVisibility(HoveredSlot ? ESlateVisibility::SelfHitTestInvisible : ESlateVisibility::Hidden); } if (!HoveredSlot) { ClearDisplay(); return; } const UItemDataAsset* Item = HoveredSlot->Item; if (ItemIcon) { if (Item->Icon) { ItemIcon->SetBrushFromTexture(Item->Icon, /*bMatchSize=*/false); ItemIcon->SetVisibility(ESlateVisibility::HitTestInvisible); } else { ItemIcon->SetVisibility(ESlateVisibility::Hidden); } } if (ItemNameText) { ItemNameText->SetText(Item->DisplayName); } if (ItemDescriptionText) { ItemDescriptionText->SetText(Item->Description); } // --- Usure --- // Meme regle que sur la case de la grille : rien a montrer sur un objet a // usage unique, et le bloc se replie plutot que de laisser un vide. const int32 MaxUses = FMath::Max(1, Item->MaxUses); const bool bHasUses = MaxUses > 1; if (UsesPanel) { UsesPanel->SetVisibility(bHasUses ? ESlateVisibility::SelfHitTestInvisible : ESlateVisibility::Collapsed); } if (bHasUses) { if (UsesBar) { UsesBar->SetPercent(FMath::Clamp(static_cast(HoveredSlot->RemainingUses) / static_cast(MaxUses), 0.f, 1.f)); } if (UsesText) { UsesText->SetText(FText::Format(INVTEXT("{0} / {1}"), FText::AsNumber(HoveredSlot->RemainingUses), FText::AsNumber(MaxUses))); } } } void UItemDetailsWidget::ClearDisplay() { if (ItemIcon) { // Hidden et non Collapsed : l'icone garde sa place, donc le nom et la // description ne remontent pas d'un cran au moment de disparaitre. ItemIcon->SetVisibility(ESlateVisibility::Hidden); } if (ItemNameText) { ItemNameText->SetText(FText::GetEmpty()); } if (ItemDescriptionText) { ItemDescriptionText->SetText(FText::GetEmpty()); } if (UsesPanel) { UsesPanel->SetVisibility(ESlateVisibility::Collapsed); } }