Files
UnrealEngine/Engine/Source/Runtime/GameMenuBuilder/Public/SGameMenuPageWidget.h
2025-05-18 13:04:45 +08:00

392 lines
11 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Math/IntPoint.h"
#include "Delegates/Delegate.h"
#include "Internationalization/Text.h"
#include "Math/Color.h"
#include "Layout/Visibility.h"
#include "Layout/Margin.h"
#include "Animation/CurveHandle.h"
#include "Animation/CurveSequence.h"
#include "Styling/ISlateStyle.h"
#include "Styling/SlateColor.h"
#include "Styling/SlateWidgetStyleAsset.h"
#include "Input/Reply.h"
#include "Widgets/DeclarativeSyntaxSupport.h"
#include "Widgets/SCompoundWidget.h"
#include "Engine/GameViewportClient.h"
#include "GameFramework/PlayerController.h"
#include "GameMenuWidgetStyle.h"
class UGameViewportClient;
class FGameMenuPage;
class SVerticalBox;
class SWidget;
struct FFocusEvent;
struct FGeometry;
struct FKeyEvent;
struct FPointerEvent;
namespace EPanelState
{
enum Type
{
/* Menu is opening. */
Opening,
/* Menu is open. */
Open,
/* Menu is closing. */
Closing,
/* Menu is closed. */
Closed
};
};
DECLARE_DELEGATE_OneParam(FPanelStateChanged, bool);
// Simple class to contain the menu panels/animations
class FMenuPanel
{
public:
FMenuPanel();
void Tick(float Delta);
/* Close the panel */
void ClosePanel(TSharedRef<SWidget> OwnerWidget);
/* Open the panel */
void OpenPanel(TSharedRef<SWidget> OwnerWidget);
/* Force the panel to be fully open. */
void ForcePanelOpen();
/* Force the panel to be fully closed. */
void ForcePanelClosed();
void SetStyle(const FGameMenuStyle* InStyle);
/* Delegate called when the panel becomes open or closed. */
FPanelStateChanged OnStateChanged;
/* Animation curve/handle for panel animation. */
FCurveHandle AnimationHandle;
/* The current state of the panel. */
EPanelState::Type CurrentState;
private:
/* Animation sequence used to open or close the panel. */
FCurveSequence AnimationSequence;
};
class FGameMenuPage;
// Simple Menu page widget class
class GAMEMENUBUILDER_API SGameMenuPageWidget : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SGameMenuPageWidget)
: _PCOwner() {}
/** style to use for this menu item. */
SLATE_STYLE_ARGUMENT(FGameMenuStyle, MenuStyle)
/** weak pointer to the parent HUD base. */
SLATE_ARGUMENT(TWeakObjectPtr<APlayerController>, PCOwner)
/** is this main menu or in game menu ? */
SLATE_ARGUMENT(bool, GameMenu)
/** always goes here */
SLATE_END_ARGS()
/** Delegate to call when in-game menu should be hidden using controller buttons -
it's workaround as when joystick is captured, even when sending FReply::Unhandled, binding does not receive input :( */
DECLARE_DELEGATE(FOnToggleMenu);
/** Delegate for selection changing. Passes old and new selection. */
DECLARE_DELEGATE_TwoParams(FOnSelectionChanged, TSharedPtr<class FGameMenuItem>, TSharedPtr<class FGameMenuItem>);
/** every widget needs a construction function. */
void Construct(const FArguments& InArgs);
//~ Begin SWidget Interface
/** Update function. */
virtual void Tick( const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime ) override;
/** Mouse button down handler. */
virtual FReply OnMouseButtonDown(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent) override;
/** Key down handler. */
virtual FReply OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent) override;
/** says that we can support keyboard focus. */
virtual bool SupportsKeyboardFocus() const override { return true; }
/** The menu sets up the appropriate mouse settings upon focus. */
virtual FReply OnFocusReceived(const FGeometry& MyGeometry, const FFocusEvent& InFocusEvent) override;
//~ End SWidget Interface
/**
* Callback handler for when the state of the main panel changes.
*
* @param bWasOpened whether the panel was opened or closed. is TRUE if panel opened.
*
*/
virtual void OnMainPanelStateChange(bool bWasOpened);
/**
* Callback handler for when the state of the sub panel changes.b
*
* @param bWasOpened whether the panel was opened or closed. is TRUE if panel opened.
*
*/
virtual void OnSubPanelStateChange(bool bWasOpened);
/** Setups misc animation sequences. */
void SetupAnimations();
/** Make the currently selected menu sub menu new main menu if valid. */
void EnterSubMenu(TSharedPtr<FGameMenuPage> InSubMenu);
/**
* Go back the the previous menu.
*
* @param bIsCancel if true will be treated as CANCEL (IE escape pressed).
*
*/
void MenuGoBack(bool bIsCancel=false);
/** Confirms current menu item and performs an action. Will also play selection sound. */
void ConfirmMenuItem();
/**
* Show the given menu and make it the current menu.
*
* @param InMenu The menu to show and set as the current menu. If this is NULL Current menu will be used if valid.
*
*/
void BuildAndShowMenu(TSharedPtr< FGameMenuPage > InMenu);
/** Hide the menu. */
void HideMenu();
/**
* Updates arrows visibility for multi-choice menu item.
*
* @param InMenuItem The item to update.
*
*/
void UpdateArrows(TSharedPtr<class FGameMenuItem> InMenuItem);
/**
* Change the currently selection option of the currently selected menu item.
*
* @param InMoveBy Number to change the option by.
*
*/
void ChangeOption(int32 InMoveBy);
/** disable/enable moving around menu. */
void LockControls(bool bEnable);
/**
* Set the current menu and 'open' it as the main panel.
*
* @param InMenu The menu to open and set as current.
*
*/
void OpenMainPanel(TSharedPtr< FGameMenuPage > InMenu);
/**
* Select a given item from an index
*
* @param InSelection The index of the item to select
* @returns true if selection changed.
*/
bool SelectItem(int32 InSelection);
void ResetMenu();
/* The viewport I am attached to. */
TWeakObjectPtr<UGameViewportClient> MyGameViewport;
TSharedPtr< FGameMenuPage > GetCurrentMenu();
protected:
/* Set the current menu. Also sets the owner widget of that menu to this and resets the previous menu owner. */
void SetCurrentMenu(TSharedPtr< FGameMenuPage > InMenu);
/** Sets hit test invisibility when console is up. */
EVisibility GetSlateVisibility() const;
/* Returns true if the submenu should be visible. */
EVisibility GetSubMenuVisiblity() const;
/** Gets current scale for drawing menu. */
float GetUIScale() const;
/**
* Rebuild the widgets in the main menu widget.
* Selected item will be set from InPreviousIndex unless it is invalid.
*
* @param InPanel The FGameMenuPage we are building the panel from.
* @param InBox The SVerticalBox in which to build the widgets from the given panel.
* @param PreviousIndex The previous menu index. (Can be INDEX_NONE)
*
*/
void BuildPanelButtons(TSharedPtr< FGameMenuPage > InPanel, TSharedPtr<SVerticalBox> InBox, int32 InPreviousIndex);
/** Misc Getters used for animating/fading various menu facets. */
FLinearColor GetPanelsColor() const;
FSlateColor GetPanelsBackgroundColor() const;
FMargin GetMainMenuOffset() const;
FMargin GetSubMenuOffset() const;
FMargin GetMenuTitleOffset() const;
FMargin GetMenuOffset() const;
FMargin GetMenuItemPadding() const;
FMargin GetSubMenuItemPadding() const;
FSlateColor GetTitleColor() const;
FSlateColor GetTextColor() const;
/**
* Callback for when one of the menu items is selected.
*
* @param SelectionIndex The index selection.
* @returns Will return UNHANDLED if the current menu is invalid, HANDLED in all other cases including if the controls are locked.
*/
virtual FReply SelectionChanged(int32 SelectionIndex);
/**
* Callback for handling mouse click.
*
* @param SelectionIndex The index selection.
* @returns Will return UNHANDLED if the current menu is invalid, HANDLED in all other cases including if the controls are locked.
*/
virtual FReply MouseButtonClicked(int32 SelectionIndex);
/**
* Gets currently selected multi-choice option.
*
* @param SelectionIndex The index selection.
* @returns Will return UNHANDLED if the current menu is invalid, HANDLED in all other cases including if the controls are locked.
*/
FText GetOptionText(TSharedPtr<class FGameMenuItem> MenuItem) const;
/** Gets current menu title string. */
FText GetMenuTitle() const;
/** Gets the menu title visibility based on if the title text is empty. */
EVisibility GetMenuTitleVisibility() const;
/** Start the main menu open fade/anim and set keyboard focu.s */
void FadeIn();
/**
* Animates the title widget.
*
* @param bShowTitle true to show the title, false to hide it.
*/
void SetTitleAnimation(bool bShowTitle);
/* Opens any pending sub menu if there is one. */
void OpenPendingSubMenu();
/** Control for hiding the menu - Defaults to start button. */
//FKey ControllerHideMenuKey;
/** Current menu title if present. */
FText CurrentMenuTitle;
/** If console is currently opened. */
bool bConsoleVisible;
/** Container instance for main panel. */
FMenuPanel MainMenuPanel;
/** Container instance for sub menu panel (only relevant with side by side layout). */
FMenuPanel SubMenuPanel;
/** Next menu (for transition and displaying as the right menu). */
TSharedPtr< FGameMenuPage > NextMenu;
/** Currently active menu. */
TSharedPtr< FGameMenuPage > CurrentMenu;
/** Current UI scale attribute. */
TAttribute<float> UIScale;
/** Our curve sequence and the related handles. */
FCurveSequence MenuWidgetAnimation;
/** Used for main menu logo fade in animation at the beginning. */
FCurveHandle TopColorCurve;
/** Used for menu background fade in animation at the beginning. */
FCurveHandle ColorFadeCurve;
/** Used for menu buttons slide in animation at the beginning. */
FCurveHandle MenuAnimationCurve;
/** Our curve sequence and the related handles. */
FCurveSequence TitleWidgetAnimation;
/* Used to animate the title widget (NYI) */
FCurveHandle TitleWidgetCurve;
/** Weak pointer to our parent Player Controller. */
TWeakObjectPtr<class APlayerController> PCOwner;
/** Screen resolution. */
FIntPoint ScreenRes;
/** Animation type index. */
int32 MainAnimNumber;
/** Selected index of current menu. */
int32 SelectedIndex;
/** Flag when playing hiding animation. */
uint8 bMenuHiding : 1;
/** Flag when playing hiding animation. */
uint8 bMenuHidden : 1;
/** If this is in game menu. */
uint8 bGameMenu : 1;
/** If moving around menu is currently locked. */
uint8 bControlsLocked : 1;
/** Menu that will override current one after transition animation. */
TSharedPtr< FGameMenuPage > PendingMainMenu;
/** Menu that will become the submenu after transition animation. */
TSharedPtr< FGameMenuPage > PendingSubMenu;
/** Current menu layout box. */
TSharedPtr<SVerticalBox> MainPanel;
/** Sub menu layout box. */
TSharedPtr<SVerticalBox> SubPanel;
/** Style to use for this menu item. */
const FGameMenuStyle* MenuStyle;
/** Stack of previous menus. */
TArray< TSharedPtr< FGameMenuPage>> MenuHistory;
/** Bind if menu should be hidden from outside by controller button. */
FOnToggleMenu OnToggleMenu;
/** Executed when the user selects an item. */
FOnSelectionChanged OnSelectionChange;
};