Files
GTASource/game/frontend/page_deck/PageViewBase.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

378 lines
10 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// FILE : PageViewBase.cpp
// PURPOSE : Base class for page views, which take page contents and visualize them
//
// AUTHOR : james.strain
// STARTED : October 2020
//
/////////////////////////////////////////////////////////////////////////////////
#include "PageViewBase.h"
#if UI_PAGE_DECK_ENABLED
#include "PageViewBase_parser.h"
// framework
#include "fwutil/xmacro.h"
// game
#include "frontend/input/uiInputCommon.h"
#include "frontend/page_deck/IPageViewHost.h"
#include "frontend/page_deck/messages/uiPageDeckMessages.h"
#include "frontend/page_deck/PageItemBase.h"
#include "frontend/page_deck/layout/PageLayoutBase.h"
#include "frontend/page_deck/layout/PageLayoutItemParams.h"
#include "frontend/VideoEditor/ui/InstructionalButtons.h"
FWUI_DEFINE_TYPE( CPageViewBase, 0x87322A73 );
void CPageViewBase::Initialize( IPageViewHost& viewHost )
{
if( uiVerifyf( !IsInitialized(), "Double initializing view" ) )
{
m_viewHost = &viewHost;
m_focused = false;
}
}
void CPageViewBase::Shutdown()
{
OnShutdown();
CleanupHotkeys();
m_pageRoot.Release();
m_viewHost = nullptr;
m_focused = false;
}
void CPageViewBase::OnEnterStart( IPageItemProvider& itemProvider )
{
uiFatalAssertf( !HasValidState(), "Double-entering a page is not supported" );
m_itemProvider = &itemProvider;
IPageViewHost& viewHost = GetViewHost();
viewHost.RegisterActivePage( *this );
m_timeoutMs = 0.f;
OnEnterStartDerived();
}
bool CPageViewBase::OnEnterUpdate( float const deltaMs )
{
bool result = false;
IPageViewHost& viewHost = GetViewHost();
if( viewHost.CanCreateContent() )
{
if( !m_pageRoot.IsActive() )
{
CComplexObject& sceneRoot = viewHost.GetSceneRoot();
m_pageRoot = sceneRoot.CreateEmptyMovieClip( nullptr, -1 );
}
result = OnEnterUpdateDerived( deltaMs );
}
return result;
}
void CPageViewBase::OnEnterComplete()
{
OnEnterCompleteDerived();
}
void CPageViewBase::OnEnterTimeout()
{
OnEnterTimeoutDerived();
}
void CPageViewBase::OnFocusGained( bool const focusFromEnter )
{
if( focusFromEnter )
{
PlayEnterAnimation();
}
m_focused = true;
OnFocusGainedDerived();
RefreshPrompts();
}
void CPageViewBase::Update( float const deltaMs )
{
if( m_pendingBackoutWarning )
{
// If you are looking to add complex logic here, please don't. You can use the BACKOUT_BLOCKED mode and then
// register a hotkey + message to the backbutton in the page deck data to achieve a highly custom backout warning instead
CWarningScreen::SetMessage( WARNING_MESSAGE_STANDARD, m_backoutWarningLabel, FE_WARNING_OK | FE_WARNING_CANCEL );
eWarningButtonFlags const c_result = CWarningScreen::CheckAllInput();
if( c_result != FE_WARNING_NONE )
{
m_pendingBackoutWarning = false;
if( ( c_result & FE_WARNING_OK ) != 0 )
{
IPageViewHost& viewHost = GetViewHost();
uiPageDeckBackMessage backMsg;
viewHost.HandleMessage( backMsg );
}
}
}
else
{
UpdateDerived( deltaMs );
UpdateVisuals();
}
}
void CPageViewBase::UpdateInput()
{
if( !m_pendingBackoutWarning )
{
if( IsViewFocused() )
{
bool handledInput = false;
IPageViewHost& viewHost = GetViewHost();
bool const c_backoutAllowed = IsBackoutAllowed();
if( c_backoutAllowed && CPauseMenu::CheckInput( FRONTEND_INPUT_BACK ) )
{
bool triggerAudio = true;
if( m_backoutMode == BACKOUT_DEFAULT )
{
uiPageDeckBackMessage backMsg;
if( viewHost.HandleMessage( backMsg ) )
{
triggerAudio = true;
}
}
else
{
m_pendingBackoutWarning = true;
}
if( triggerAudio )
{
TriggerInputAudio( fwuiInput::ACTION_HANDLED, "BACK", nullptr );
}
}
else
{
auto inputFunc = [&handledInput,&viewHost]( uiPageHotkey& hotkey )
{
eFRONTEND_INPUT const c_input = hotkey.GetFrontendInputType();
if( CPauseMenu::CheckInput( c_input, true ) )
{
viewHost.HandleMessage( *hotkey.GetMessage() );
handledInput = true;
}
};
ForEachHotkey( inputFunc );
if( !handledInput )
{
UpdateInputDerived();
}
}
}
}
}
void CPageViewBase::UpdateVisuals()
{
UpdateVisualsDerived();
}
void CPageViewBase::OnFocusLost()
{
m_focused = false;
OnFocusLostDerived();
}
void CPageViewBase::OnExitStart()
{
m_timeoutMs = 0.f;
OnExitStartDerived();
}
bool CPageViewBase::OnExitUpdate( float const deltaMs )
{
return OnExitUpdateDerived( deltaMs );
}
void CPageViewBase::OnExitComplete( IPageItemProvider& ASSERT_ONLY(itemProvider) )
{
OnExitCompleteDerived();
m_pageRoot.Release();
IPageViewHost& viewHost = GetViewHost();
viewHost.UnregisterActivePage( *this );
uiFatalAssertf( m_itemProvider == &itemProvider, "Exiting page with wrong item provider. Caller logic is very broken" );
m_itemProvider = nullptr;
m_pendingBackoutWarning = false;
}
CPageViewBase::CPageViewBase()
: superclass()
, m_viewHost( nullptr )
, m_itemProvider( nullptr )
, m_backOutLabel()
, m_acceptLabel()
, m_timeoutMs( 0.f )
, m_backoutMode( BACKOUT_DEFAULT )
, m_focused( false )
, m_pendingBackoutWarning( false )
{
}
void CPageViewBase::TriggerInputAudio( fwuiInput::eHandlerResult const actionResult, char const * const actionedTrigger, char const * const ignoredTrigger ) const
{
char const * const c_audioSoundset = GetAudioSoundset();
uiInput::TriggerInputAudio( actionResult, c_audioSoundset, actionedTrigger, ignoredTrigger );
}
char const * const CPageViewBase::GetAudioSoundset()
{
// TODO_UI - We can parGen this if required for different views
return "UI_Landing_Screen_Extended_Sounds";
}
void CPageViewBase::UpdateInstructionalButtonsDerived()
{
if( IsBackoutAllowed() )
{
IPageViewHost& viewHost = GetViewHost();
uiPageDeckCanBackOutMessage canBackOutMsg;
if( viewHost.HandleMessage( canBackOutMsg ) && canBackOutMsg.GetResult() )
{
char const * const c_label = GetBackoutPromptText();
CVideoEditorInstructionalButtons::AddButton( rage::INPUT_FRONTEND_CANCEL, c_label, true );
}
}
auto ibFunc = []( uiPageHotkey const& hotkey )
{
char const * const c_label = TheText.Get( hotkey.GetLabel() );
CVideoEditorInstructionalButtons::AddButton( hotkey.GetHotkeyInputType(), c_label, true );
};
ForEachHotkey( ibFunc );
}
void CPageViewBase::InitializeTooltip( CComplexObject& parentObject, CPageLayoutBase& layout, CPageLayoutItemParams const& params )
{
m_tooltip.Initialize( parentObject );
layout.RegisterItem( m_tooltip, params );
}
void CPageViewBase::ShutdownTooltip()
{
m_tooltip.Shutdown();
}
void CPageViewBase::SetTooltipLiteral( char const * const tooltipText, bool isRichText )
{
m_tooltip.SetStringLiteral( tooltipText, isRichText);
}
void CPageViewBase::RefreshPrompts()
{
CVideoEditorInstructionalButtons::Refresh();
}
void CPageViewBase::ClearPromptsAndTooltip()
{
CVideoEditorInstructionalButtons::Refresh();
ClearTooltip();
}
void CPageViewBase::ClearTooltip()
{
m_tooltip.SetStringLiteral( "", false );
}
bool CPageViewBase::AreAllItemTexturesAvailable() const
{
bool areAllTexturesAvailable = true;
IPageItemProvider const& c_itemProvider = GetItemProvider();
auto itemFunc = [&areAllTexturesAvailable]( CPageItemBase const& item )
{
IItemTextureInterface const * const c_textureInterface = item.GetTextureInterface();
bool const c_itemTexturesAvailable = c_textureInterface == nullptr || c_textureInterface->IsTextureAvailable();
areAllTexturesAvailable = areAllTexturesAvailable && c_itemTexturesAvailable;
};
auto categoryFunc = [&itemFunc]( CPageItemCategoryBase const& category )
{
category.ForEachItem( itemFunc );
};
c_itemProvider.ForEachCategory( categoryFunc );
return areAllTexturesAvailable;
}
bool CPageViewBase::OnEnterUpdateDerived( float const deltaMs )
{
m_timeoutMs += deltaMs;
return true;
}
bool CPageViewBase::OnExitUpdateDerived(float const deltaMs)
{
m_timeoutMs += deltaMs;
return true;
}
bool CPageViewBase::OnEnterTimeoutDerived()
{
return true;
}
char const * CPageViewBase::GetAcceptPromptText() const
{
return uiPageConfig::GetLabel( ATSTRINGHASH( "IB_SELECT", 0xD7ED7F0C ), m_acceptLabel );
}
char const * CPageViewBase::GetBackoutPromptText() const
{
return uiPageConfig::GetLabel( ATSTRINGHASH( "IB_BACK", 0xE5FC11CD ), m_backOutLabel );
}
void CPageViewBase::ForEachHotkey( HotkeyLambda action )
{
int const c_count = m_hotkeyMapping.GetCount();
for( int index = 0; index < c_count; ++index )
{
uiPageHotkey * const entry = m_hotkeyMapping[index];
if( entry && entry->IsValid() )
{
action( *entry );
}
}
}
void CPageViewBase::ForEachHotkey( HotkeyConstLambda action ) const
{
int const c_count = m_hotkeyMapping.GetCount();
for( int index = 0; index < c_count; ++index )
{
uiPageHotkey const * const c_entry = m_hotkeyMapping[index];
if( c_entry && c_entry->IsValid() )
{
action( *c_entry );
}
}
}
void CPageViewBase::CleanupHotkeys()
{
auto shutdownFunc = []( uiPageHotkey& hotkey )
{
delete &hotkey;
};
ForEachHotkey( shutdownFunc );
m_hotkeyMapping.ResetCount();
}
#endif // UI_PAGE_DECK_ENABLED