(Feat) Add MainMenu

This commit is contained in:
2026-07-28 14:10:17 +02:00
parent ed7c7fd991
commit 175bef228c
33 changed files with 2331 additions and 12 deletions
@@ -0,0 +1,268 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "SettingsMenuWidget.h"
#include "Components/Button.h"
#include "Components/WidgetSwitcher.h"
#include "ConfirmDialogWidget.h"
#include "InputCoreTypes.h"
#include "SettingsTabWidget.h"
#include "SurvivalUserSettings.h"
#define LOCTEXT_NAMESPACE "Reglages"
namespace
{
// Ordre des pages dans le WidgetSwitcher. Les trois dernieres n'existent pas
// encore : leur bouton se grise tout seul tant que la page est absente.
constexpr int32 TabIndexGameplay = 0;
constexpr int32 TabIndexDisplay = 1;
constexpr int32 TabIndexGraphics = 2;
constexpr int32 TabIndexAudio = 3;
}
USettingsMenuWidget::USettingsMenuWidget(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// Sans ce drapeau le widget ne peut pas prendre le focus clavier, et
// NativeOnKeyDown ne serait jamais appele. Il ne se change qu'a la
// construction, d'ou sa presence ici et pas dans Open().
SetIsFocusable(true);
ResetDialogMessage = LOCTEXT("ResetConfirm", "Réinitialiser cet onglet ?");
}
void USettingsMenuWidget::NativeConstruct()
{
Super::NativeConstruct();
if (BackButton)
{
BackButton->OnClicked.AddDynamic(this, &USettingsMenuWidget::HandleBackClicked);
}
if (ResetButton)
{
ResetButton->OnClicked.AddDynamic(this, &USettingsMenuWidget::HandleResetClicked);
}
if (GameplayTabButton)
{
GameplayTabButton->OnClicked.AddDynamic(this, &USettingsMenuWidget::HandleGameplayTabClicked);
}
if (DisplayTabButton)
{
DisplayTabButton->OnClicked.AddDynamic(this, &USettingsMenuWidget::HandleDisplayTabClicked);
}
if (GraphicsTabButton)
{
GraphicsTabButton->OnClicked.AddDynamic(this, &USettingsMenuWidget::HandleGraphicsTabClicked);
}
if (AudioTabButton)
{
AudioTabButton->OnClicked.AddDynamic(this, &USettingsMenuWidget::HandleAudioTabClicked);
}
if (ResetDialog)
{
ResetDialog->OnConfirmed.AddDynamic(this, &USettingsMenuWidget::HandleResetConfirmed);
ResetDialog->OnCancelled.AddDynamic(this, &USettingsMenuWidget::HandleResetCancelled);
ResetDialog->Close();
}
UpdateTabButtonStates();
}
void USettingsMenuWidget::NativeDestruct()
{
if (BackButton)
{
BackButton->OnClicked.RemoveDynamic(this, &USettingsMenuWidget::HandleBackClicked);
}
if (ResetButton)
{
ResetButton->OnClicked.RemoveDynamic(this, &USettingsMenuWidget::HandleResetClicked);
}
Super::NativeDestruct();
}
void USettingsMenuWidget::Open()
{
SetVisibility(ESlateVisibility::Visible);
// L'ecran a pu etre ouvert, referme, puis rouvert apres un changement fait
// ailleurs : on relit toujours plutot que de faire confiance a l'affichage.
if (USettingsTabWidget* ActiveTab = GetActiveTab())
{
ActiveTab->RefreshFromSettings();
}
// Le focus doit etre repris a CHAQUE ouverture, sinon Echap reste sans effet.
SetKeyboardFocus();
}
void USettingsMenuWidget::Close()
{
if (ResetDialog)
{
ResetDialog->Close();
}
bResetDialogOpen = false;
SetVisibility(ESlateVisibility::Collapsed);
// La sauvegarde a lieu ici et pas a chaque clic de fleche : ecrire le .ini
// vingt fois pendant qu'on cherche la bonne sensibilite ne sert a rien.
if (USurvivalUserSettings* Settings = USurvivalUserSettings::Get())
{
Settings->SaveSettings();
}
}
FReply USettingsMenuWidget::NativeOnKeyDown(const FGeometry& InGeometry, const FKeyEvent& InKeyEvent)
{
const FKey Key = InKeyEvent.GetKey();
if (Key == EKeys::Escape)
{
// La boite de confirmation gere Echap elle-meme quand elle a le focus.
// Si elle l'a perdu, on annule ici plutot que de fermer tout l'ecran en
// laissant la question affichee.
if (bResetDialogOpen)
{
HandleResetCancelled();
return FReply::Handled();
}
OnCloseRequested.Broadcast();
// Handled : sans ca la touche continue de remonter et le menu de pause
// la consommerait une seconde fois.
return FReply::Handled();
}
return Super::NativeOnKeyDown(InGeometry, InKeyEvent);
}
USettingsTabWidget* USettingsMenuWidget::GetActiveTab() const
{
return TabSwitcher ? Cast<USettingsTabWidget>(TabSwitcher->GetActiveWidget()) : nullptr;
}
void USettingsMenuWidget::ShowTab(int32 Index)
{
if (!TabSwitcher || Index < 0 || Index >= TabSwitcher->GetNumWidgets())
{
return;
}
TabSwitcher->SetActiveWidgetIndex(Index);
if (USettingsTabWidget* ActiveTab = GetActiveTab())
{
ActiveTab->RefreshFromSettings();
}
}
void USettingsMenuWidget::UpdateTabButtonStates()
{
const int32 PageCount = TabSwitcher ? TabSwitcher->GetNumWidgets() : 0;
if (GameplayTabButton)
{
GameplayTabButton->SetIsEnabled(PageCount > TabIndexGameplay);
}
if (DisplayTabButton)
{
DisplayTabButton->SetIsEnabled(PageCount > TabIndexDisplay);
}
if (GraphicsTabButton)
{
GraphicsTabButton->SetIsEnabled(PageCount > TabIndexGraphics);
}
if (AudioTabButton)
{
AudioTabButton->SetIsEnabled(PageCount > TabIndexAudio);
}
}
void USettingsMenuWidget::HandleBackClicked()
{
OnCloseRequested.Broadcast();
}
void USettingsMenuWidget::HandleResetClicked()
{
// Sans boite assignee on ne bloque pas le joueur : on reinitialise.
if (!ResetDialog)
{
HandleResetConfirmed();
return;
}
bResetDialogOpen = true;
ResetDialog->Open(ResetDialogMessage);
}
void USettingsMenuWidget::HandleResetConfirmed()
{
bResetDialogOpen = false;
if (ResetDialog)
{
ResetDialog->Close();
}
// Uniquement l'onglet visible : un "Reinitialiser" qui remettrait aussi la
// resolution et le volume serait une mauvaise surprise.
if (USettingsTabWidget* ActiveTab = GetActiveTab())
{
ActiveTab->ResetToDefaults();
}
SetKeyboardFocus();
}
void USettingsMenuWidget::HandleResetCancelled()
{
bResetDialogOpen = false;
if (ResetDialog)
{
ResetDialog->Close();
}
SetKeyboardFocus();
}
void USettingsMenuWidget::HandleGameplayTabClicked()
{
ShowTab(TabIndexGameplay);
}
void USettingsMenuWidget::HandleDisplayTabClicked()
{
ShowTab(TabIndexDisplay);
}
void USettingsMenuWidget::HandleGraphicsTabClicked()
{
ShowTab(TabIndexGraphics);
}
void USettingsMenuWidget::HandleAudioTabClicked()
{
ShowTab(TabIndexAudio);
}
#undef LOCTEXT_NAMESPACE