Files
Unreal_EmberWild/Source/EmberWild/Public/SettingsMenuWidget.h
T

241 lines
7.8 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "SettingsMenuWidget.generated.h"
class UButton;
class UConfirmDialogWidget;
class UKeyCaptureWidget;
class USettingsTabWidget;
class UWidgetSwitcher;
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnSettingsCloseRequested);
/** Reponse a une demande de confirmation. bConfirmed est faux sur un refus ou une expiration. */
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnSettingsConfirmationResult, bool, bConfirmed);
/** Touche capturee. Invalide si le joueur a annule avec Echap. */
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnSettingsKeyCaptureResult, FKey, CapturedKey);
/**
* L'ecran de reglages : une barre d'onglets, un WidgetSwitcher, Retour et
* Reinitialiser.
*
* Il ne sait PAS qui l'a ouvert. Il demande a se fermer via OnCloseRequested et
* c'est l'appelant -- menu principal ou menu de pause -- qui decide de ce que
* "Retour" veut dire. Sans ca il faudrait un ecran par contexte.
*
* Il ne connait pas davantage le contenu de ses onglets : il appelle
* RefreshFromSettings et ResetToDefaults sur USettingsTabWidget. Ajouter
* l'onglet Graphismes ne demandera aucune ligne ici.
*
* Classe Abstract : on cree un WBP_Settings qui en herite.
*/
UCLASS(Abstract)
class EMBERWILD_API USettingsMenuWidget : public UUserWidget
{
GENERATED_BODY()
public:
USettingsMenuWidget(const FObjectInitializer& ObjectInitializer);
virtual void NativeConstruct() override;
virtual void NativeDestruct() override;
virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override;
UPROPERTY(BlueprintAssignable, Category = "Reglages")
FOnSettingsCloseRequested OnCloseRequested;
/**
* Affiche l'ecran, rafraichit l'onglet visible et prend le focus clavier.
*
* Passe par ici et jamais par SetVisibility : sans le focus, Echap ne
* refermerait pas l'ecran.
*/
UFUNCTION(BlueprintCallable, Category = "Reglages")
void Open();
/** Masque l'ecran et ecrit le fichier de reglages. */
UFUNCTION(BlueprintCallable, Category = "Reglages")
void Close();
/**
* ZOrder de la boite de confirmation, impose par celui qui ouvre l'ecran.
*
* L'ecran ne le choisit PAS lui-meme : il est ouvert depuis deux contextes
* dont les empilements n'ont rien a voir (50 au menu principal, 150 en jeu).
* Un numero code en dur ici obligerait le widget a savoir qui l'affiche,
* exactement ce qu'on evite avec OnCloseRequested. A appeler AVANT Open().
*/
UFUNCTION(BlueprintCallable, Category = "Reglages")
void SetDialogZOrder(int32 InZOrder) { DialogZOrder = InZOrder; }
/**
* Pose une question au joueur pour le compte d'un onglet.
*
* L'ecran est le seul a posseder une boite : un onglet qui creerait la
* sienne devrait a son tour se demander a quel ZOrder la poser, et on
* repartirait pour un tour.
*
* @param MessageOrFormat texte simple, ou format contenant {0} si
* CountdownSeconds est superieur a zero.
* @param CountdownSeconds 0 pour une question sans limite de temps.
* @return false si aucune boite n'est configuree -- l'appelant doit alors
* decider seul, sa reponse n'arrivera jamais.
*/
bool RequestConfirmation(const FText& MessageOrFormat, float CountdownSeconds, const FOnSettingsConfirmationResult& OnResult);
/**
* Ouvre le voile de capture de touche pour le compte d'un onglet.
*
* Meme raison que la boite : un voile pose DANS l'onglet serait clippe a la
* zone du WidgetSwitcher au lieu de couvrir l'ecran, et devrait a son tour
* se trouver un ZOrder.
*
* @return false si aucun voile n'est configure -- la reponse n'arrivera
* jamais, l'appelant doit renoncer.
*/
bool RequestKeyCapture(const FText& ActionLabel, const FOnSettingsKeyCaptureResult& OnResult);
/**
* Bascule le voile deja ouvert sur la question de conflit.
*
* Le voile RESTE ouvert entre la capture et la reponse : c'est le meme geste
* pour le joueur, il n'a pas a le voir disparaitre puis revenir.
*/
UFUNCTION(BlueprintCallable, Category = "Reglages")
void ShowKeyCaptureConflict(const FText& Message, const FOnSettingsConfirmationResult& OnAnswer);
/** Referme le voile. A appeler quand le remappage est termine ou abandonne. */
UFUNCTION(BlueprintCallable, Category = "Reglages")
void CloseKeyCapture();
protected:
UPROPERTY(meta = (BindWidget))
TObjectPtr<UWidgetSwitcher> TabSwitcher;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> BackButton;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> ResetButton;
/**
* Les cinq onglets sont OBLIGATOIRES : un WBP_Settings sans eux ne compile pas.
*
* BindWidgetOptional echoue en silence -- un nom mal orthographie donnait un
* bouton parfaitement inerte, sans le moindre message. Pour un element dont
* l'absence n'a aucun sens, on veut l'erreur a la compilation du Blueprint.
*/
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> GameplayTabButton;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> DisplayTabButton;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> GraphicsTabButton;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> ControlsTabButton;
UPROPERTY(meta = (BindWidget))
TObjectPtr<UButton> AudioTabButton;
/**
* Ton WBP_ConfirmDialog, a renseigner dans les Class Defaults de
* WBP_Settings. Laisse-le vide et "Reinitialiser" agit sans rien demander.
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Reglages")
TSubclassOf<UConfirmDialogWidget> ResetDialogClass;
/** La question posee avant de reinitialiser l'onglet visible. */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Reglages")
FText ResetDialogMessage;
/** Ton WBP_KeyCapture. Sans lui, l'onglet Touches ne peut rien remapper. */
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Reglages")
TSubclassOf<UKeyCaptureWidget> KeyCaptureClass;
UPROPERTY(Transient, BlueprintReadOnly, Category = "Reglages")
TObjectPtr<UConfirmDialogWidget> ResetDialog;
UPROPERTY(Transient, BlueprintReadOnly, Category = "Reglages")
TObjectPtr<UKeyCaptureWidget> KeyCapture;
private:
UFUNCTION()
void HandleBackClicked();
UFUNCTION()
void HandleResetClicked();
/** Reponse a la question du bouton Reinitialiser. */
UFUNCTION()
void HandleResetAnswered(bool bConfirmed);
UFUNCTION()
void HandleDialogConfirmed();
UFUNCTION()
void HandleDialogCancelled();
/** Referme la boite et rend la reponse a qui a pose la question. */
void FinishConfirmation(bool bConfirmed);
/** Cree la boite au premier besoin. Renvoie nullptr si aucune classe n'est assignee. */
UConfirmDialogWidget* EnsureDialog();
UFUNCTION()
void HandleGameplayTabClicked();
UFUNCTION()
void HandleDisplayTabClicked();
UFUNCTION()
void HandleGraphicsTabClicked();
UFUNCTION()
void HandleControlsTabClicked();
UFUNCTION()
void HandleAudioTabClicked();
UFUNCTION()
void HandleKeyCaptured(FKey CapturedKey);
UFUNCTION()
void HandleKeyCaptureCancelled();
UFUNCTION()
void HandleKeyConflictAnswered(bool bConfirmed);
/** A qui rendre la reponse du conflit affiche dans le voile. */
FOnSettingsConfirmationResult PendingConflictAnswer;
/** Change de page et rafraichit la nouvelle. Ignore un index inexistant. */
void ShowTab(int32 Index);
/** La page actuellement affichee, ou nullptr si le switcher est vide. */
USettingsTabWidget* GetActiveTab() const;
/** Grise les boutons dont la page n'existe pas encore. */
void UpdateTabButtonStates();
/** A qui rendre la reponse de la boite ouverte. Vide quand rien n'est pose. */
FOnSettingsConfirmationResult PendingConfirmation;
/** A qui rendre la touche capturee. Vide quand le voile est ferme. */
FOnSettingsKeyCaptureResult PendingKeyCapture;
bool bResetDialogOpen = false;
bool bKeyCaptureOpen = false;
/** Valeur de repli si l'appelant oublie SetDialogZOrder : devant le fondu exclu. */
int32 DialogZOrder = 500;
};