// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Blueprint/UserWidget.h" #include "InputCoreTypes.h" #include "KeyCaptureWidget.generated.h" class UButton; class UTextBlock; DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnKeyCaptured, FKey, CapturedKey); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnKeyCaptureCancelled); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnKeyConflictAnswered, bool, bConfirmed); /** Ce que le voile attend a un instant donne. */ UENUM() enum class EKeyCaptureState : uint8 { /** Ferme. */ Idle, /** Ouvert, en attente d'une touche. Les boutons sont replies. */ Capturing, /** Ouvert, la touche est prise : on demande quoi faire. Les boutons apparaissent. */ Conflict }; /** * Le voile de remappage, en deux temps : "Appuie sur une touche", puis * eventuellement "cette touche est deja prise, on la vole ?". * * Les deux etapes vivent dans le MEME widget et non dans deux ecrans successifs. * Le conflit fait partie du geste de remappage : refermer le voile pour ouvrir * une boite par-dessus produirait un clignotement et ferait perdre le fil de ce * qu'on etait en train de modifier. UConfirmDialogWidget garde les questions * generiques -- reinitialiser, abandonner une partie, valider une resolution. * * Classe Abstract : on cree un WBP_KeyCapture qui en herite. */ UCLASS(Abstract) class EMBERWILD_API UKeyCaptureWidget : public UUserWidget { GENERATED_BODY() public: UKeyCaptureWidget(const FObjectInitializer& ObjectInitializer); virtual void NativeOnInitialized() override; virtual FReply NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent) override; virtual FReply NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent) override; UPROPERTY(BlueprintAssignable, Category = "Reglages") FOnKeyCaptured OnKeyCaptured; UPROPERTY(BlueprintAssignable, Category = "Reglages") FOnKeyCaptureCancelled OnCaptureCancelled; UPROPERTY(BlueprintAssignable, Category = "Reglages") FOnKeyConflictAnswered OnConflictAnswered; /** Affiche le voile, ecrit la consigne, replie les boutons et prend le focus. */ UFUNCTION(BlueprintCallable, Category = "Reglages") void BeginCapture(const FText& ActionLabel); /** * Bascule le voile deja ouvert sur la question de conflit. * * Ne referme rien : c'est tout l'interet d'avoir garde un seul widget. */ UFUNCTION(BlueprintCallable, Category = "Reglages") void ShowConflict(const FText& Message); UFUNCTION(BlueprintCallable, Category = "Reglages") void EndCapture(); UFUNCTION(BlueprintPure, Category = "Reglages") EKeyCaptureState GetCaptureState() const { return State; } protected: /** Optionnel : un voile dont le texte est fige dans le Blueprint reste valide. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr PromptText; /** * Boutons de la seule etape de conflit. Replies pendant la capture : les * afficher inertes inviterait a cliquer alors qu'on attend une touche. */ UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr ConfirmButton; UPROPERTY(meta = (BindWidgetOptional)) TObjectPtr CancelButton; /** Doit contenir {0}, remplace par le nom de l'action en cours de remappage. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Reglages") FText PromptFormat; private: UFUNCTION() void HandleConfirmClicked(); UFUNCTION() void HandleCancelClicked(); /** Facteur commun a NativeOnKeyDown et NativeOnMouseButtonDown. */ FReply CaptureKey(const FKey& Key); /** Affiche ou replie les deux boutons selon l'etat. */ void UpdateButtonVisibility(); EKeyCaptureState State = EKeyCaptureState::Idle; };