Files

124 lines
3.9 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Containers/Ticker.h"
#include "ConfirmDialogWidget.generated.h"
class UButton;
class UTextBlock;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnConfirmDialogConfirmed);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnConfirmDialogCancelled);
/**
* Boite de dialogue "es-tu sur ?", volontairement generique.
*
* Elle ne sait pas ce qu'elle confirme : elle pose la question et previent via
* ses delegues. C'est l'appelant qui decide de l'action. Ainsi la meme boite
* servira pour quitter, effacer une sauvegarde ou abandonner une partie.
*
* Classe Abstract : on cree un WBP_ConfirmDialog qui en herite.
*/
UCLASS(Abstract)
class SURVIVAL_PROJET_API UConfirmDialogWidget : public UUserWidget
{
GENERATED_BODY()
public:
UConfirmDialogWidget(const FObjectInitializer& ObjectInitializer);
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override;
UPROPERTY(BlueprintAssignable, Category = "Dialogue")
FOnConfirmDialogConfirmed OnConfirmed;
UPROPERTY(BlueprintAssignable, Category = "Dialogue")
FOnConfirmDialogCancelled OnCancelled;
/**
* Affiche la boite et lui donne le focus clavier.
*
* Passe par ici et jamais par SetVisibility directement : sans le focus,
* la boite ne recevrait aucune touche et Echap resterait sans effet.
*/
UFUNCTION(BlueprintCallable, Category = "Dialogue")
void Open(const FText& InMessage);
/**
* Meme chose, mais avec un retour automatique passe le delai.
*
* @param InMessageFormat doit contenir {0}, remplace par les secondes
* restantes. Exemple : "Garder ce mode ?\nRetour
* automatique dans {0} s."
*
* A l'expiration, OnCancelled est diffuse -- comme si le joueur avait
* refuse. C'est le seul filet quand la question porte sur un changement qui
* peut rendre l'ecran illisible.
*/
UFUNCTION(BlueprintCallable, Category = "Dialogue")
void OpenWithCountdown(const FText& InMessageFormat, float Seconds);
/** Referme la boite. Ne previent personne : l'appelant sait ce qu'il fait. */
UFUNCTION(BlueprintCallable, Category = "Dialogue")
void Close();
protected:
/** Echap equivaut a cliquer Annuler. Decoche pour une question incontournable. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialogue")
bool bCancelOnEscape = true;
/**
* Entree equivaut a cliquer Confirmer.
*
* Desactive par defaut, volontairement : sur une question destructrice, un
* joueur qui martele Entree validerait sans avoir lu.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Dialogue")
bool bConfirmOnEnter = false;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> ConfirmButton;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> CancelButton;
/** Optionnel : une boite dont le texte est fige dans le Blueprint reste valide. */
UPROPERTY(meta = (BindWidgetOptional))
TObjectPtr<UTextBlock> MessageText;
private:
UFUNCTION()
void HandleConfirmClicked();
UFUNCTION()
void HandleCancelClicked();
/** Un tick par frame tant que le rebours tourne. Renvoie false pour s'arreter. */
bool TickCountdown(float DeltaTime);
void StopCountdown();
void RefreshCountdownText();
/**
* Le rebours passe par le ticker du moteur et non par un timer du monde.
*
* Deux raisons : l'ecran de reglages s'ouvre depuis le menu de PAUSE, ou les
* timers du monde sont geles -- le rebours ne repartirait jamais ; et un
* changement de resolution rate doit se defaire meme si le jeu bloque.
*/
FTSTicker::FDelegateHandle CountdownTickerHandle;
FText CountdownMessageFormat;
float CountdownRemaining = 0.f;
/** Evite de reecrire le texte 60 fois par seconde pour rien. */
int32 LastDisplayedSeconds = -1;
};