// Fill out your copyright notice in the Description page of Project Settings.


#include "KeyCaptureWidget.h"

#include "Components/Button.h"
#include "Components/TextBlock.h"

#define LOCTEXT_NAMESPACE "Reglages"

UKeyCaptureWidget::UKeyCaptureWidget(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	// Sans ce drapeau le widget ne peut pas prendre le focus clavier, et
	// NativeOnKeyDown ne serait jamais appele -- le voile resterait affiche sans
	// jamais rien capturer. Meme piege que UConfirmDialogWidget.
	SetIsFocusable(true);

	PromptFormat = LOCTEXT("CapturePrompt", "Appuie sur une touche pour « {0} »\nÉchap pour annuler");
}

void UKeyCaptureWidget::NativeOnInitialized()
{
	Super::NativeOnInitialized();

	if (ConfirmButton)
	{
		ConfirmButton->OnClicked.AddDynamic(this, &UKeyCaptureWidget::HandleConfirmClicked);
	}

	if (CancelButton)
	{
		CancelButton->OnClicked.AddDynamic(this, &UKeyCaptureWidget::HandleCancelClicked);
	}
}

void UKeyCaptureWidget::BeginCapture(const FText& ActionLabel)
{
	State = EKeyCaptureState::Capturing;

	if (PromptText)
	{
		PromptText->SetText(FText::Format(PromptFormat, ActionLabel));
	}

	UpdateButtonVisibility();

	SetVisibility(ESlateVisibility::Visible);

	// Le focus se reprend a CHAQUE ouverture : le refermer le rend a l'ecran de
	// reglages, et un voile visible mais sans focus ignorerait le clavier.
	SetKeyboardFocus();
}

void UKeyCaptureWidget::ShowConflict(const FText& Message)
{
	State = EKeyCaptureState::Conflict;

	if (PromptText)
	{
		PromptText->SetText(Message);
	}

	UpdateButtonVisibility();

	// Le voile n'a pas bouge, mais le focus a pu partir sur un bouton qui vient
	// d'apparaitre : on le reprend pour qu'Echap continue de repondre.
	SetKeyboardFocus();
}

void UKeyCaptureWidget::EndCapture()
{
	State = EKeyCaptureState::Idle;

	UpdateButtonVisibility();
	SetVisibility(ESlateVisibility::Collapsed);
}

void UKeyCaptureWidget::UpdateButtonVisibility()
{
	// Collapsed et non Hidden : replies, les boutons ne doivent pas reserver la
	// place qu'ils occuperont, sinon la consigne de capture serait decentree.
	const ESlateVisibility ButtonVisibility = State == EKeyCaptureState::Conflict
		? ESlateVisibility::Visible
		: ESlateVisibility::Collapsed;

	if (ConfirmButton)
	{
		ConfirmButton->SetVisibility(ButtonVisibility);
	}

	if (CancelButton)
	{
		CancelButton->SetVisibility(ButtonVisibility);
	}
}

FReply UKeyCaptureWidget::NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent)
{
	const FKey Key = InKeyEvent.GetKey();

	if (State == EKeyCaptureState::Conflict)
	{
		// Echap vaut Annuler, comme partout ailleurs dans les menus.
		if (Key == EKeys::Escape)
		{
			OnConflictAnswered.Broadcast(false);
		}

		// Aucune autre touche n'est lue : on ne capture plus, on attend une
		// reponse. Sans ce garde-fou, appuyer sur une touche pour "repondre"
		// relancerait un remappage a l'insu du joueur.
		return FReply::Handled();
	}

	return CaptureKey(Key);
}

FReply UKeyCaptureWidget::NativeOnMouseButtonDown(const FGeometry& InGeometry, const FPointerEvent& InMouseEvent)
{
	if (State == EKeyCaptureState::Conflict)
	{
		// Les clics sur les boutons ne remontent pas jusqu'ici, ils sont traites
		// avant. Tout le reste est avale pour garder le voile modal.
		return FReply::Handled();
	}

	// La souris passe par le meme chemin que le clavier : Souris 4 et Souris 5
	// sont des touches comme les autres pour Enhanced Input.
	return CaptureKey(InMouseEvent.GetEffectingButton());
}

FReply UKeyCaptureWidget::CaptureKey(const FKey& Key)
{
	if (Key == EKeys::Escape)
	{
		OnCaptureCancelled.Broadcast();
		return FReply::Handled();
	}

	// Les touches de modification seules ne sont pas capturees : Enhanced Input
	// les traite comme des touches a part entiere, mais assigner "Maj" tout court
	// rendrait inutilisable toute combinaison la contenant.
	if (Key.IsModifierKey())
	{
		return FReply::Handled();
	}

	// Un axe analogique n'est pas assignable a une action Digital : on ignore
	// plutot que de laisser MapPlayerKey echouer plus loin sans explication.
	if (Key.IsAxis1D() || Key.IsAxis2D() || Key.IsAxis3D())
	{
		return FReply::Handled();
	}

	OnKeyCaptured.Broadcast(Key);

	// Handled dans tous les cas : le voile est modal, rien ne doit passer a
	// travers pendant qu'il attend une touche.
	return FReply::Handled();
}

void UKeyCaptureWidget::HandleConfirmClicked()
{
	OnConflictAnswered.Broadcast(true);
}

void UKeyCaptureWidget::HandleCancelClicked()
{
	OnConflictAnswered.Broadcast(false);
}

#undef LOCTEXT_NAMESPACE
