//========= Copyright (C) 1996-2013, Valve Corporation, All rights reserved. ============// // // Purpose: Helper for UI components - used for binding to both Scaleform ActionScript and // Panorama Javascript. // // $NoKeywords: $ //=============================================================================// #ifndef UICOMPONENT_COMMON_H #define UICOMPONENT_COMMON_H #ifdef _WIN32 #pragma once #endif #define USE_SCALEFORM_BINDINGS #if defined ( PANORAMA_ENABLE ) #define USE_PANORAMA_BINDINGS #endif // PANORAMA_ENABLE // Scaleform events are simply KeyValue objects, so it's possible to test defining, declaring and broadcasting events // in isolation without including Scaleform headers using the define below. //#define TEST_SCALEFORM_EVENTS #ifndef CSGO_PORT // In Source1 the pointers_to_members pragma is used within Scaleform and VGUI headers to ensure member function pointers // are maximum size. This affects the panorama javascript bindings (see uijsregistration.h). // We also add the pragma here so that we always assume the larger size pointers in source 1 for consistency, regardless // of the order of includes. #define MEMBER_FUNCPTRS_MAXSIZE #pragma pointers_to_members( full_generality, virtual_inheritance ) #endif #ifdef USE_SCALEFORM_BINDINGS #include "scaleformui/scaleformui.h" #endif #ifdef USE_PANORAMA_BINDINGS #include "panorama/uijsregistration.h" #include "panorama/iuiengine.h" #define DECLARE_PANORAMA_JSREGISTERFUNC void JSRegisterFunc(); #else #define DECLARE_PANORAMA_JSREGISTERFUNC #endif #include "bannedwords.h" class IUiComponentGlobalInstanceBase { public: virtual void Tick() {} virtual void Shutdown() = 0; virtual void InstallScaleformBindings( int iSlot ) = 0; virtual void InstallPanoramaBindings() = 0; virtual void ShutdownComponentApiDef(int iSlot) = 0; }; template < class T > class CUiComponentGlobalInstanceHelper : public IUiComponentGlobalInstanceBase { protected: static T* & InternalInstancePtr() { static T* s_pInstance = NULL; return s_pInstance; } public: static T* GetInstance() { if ( !InternalInstancePtr() ) { InternalInstancePtr() = new T(); } return InternalInstancePtr(); } void Shutdown() OVERRIDE { T *pInstance = InternalInstancePtr(); Assert( pInstance && (pInstance == this) ); if ( pInstance && (pInstance == this) ) { InternalInstancePtr() = NULL; delete pInstance; } } }; #define UI_COMPONENT_DECLARE_GLOBAL_INSTANCE_ONLY( classname ) \ protected: \ friend class CUiComponentGlobalInstanceHelper< classname >; \ void InstallScaleformBindings( int iSlot ) OVERRIDE; \ void InstallPanoramaBindings( ) OVERRIDE; \ void ShutdownComponentApiDef( int iSlot ) OVERRIDE; \ classname(); \ ~classname(); \ private: \ classname( const classname & other ); \ classname & operator = ( const classname & other ); \ DECLARE_PANORAMA_JSREGISTERFUNC #if defined (USE_SCALEFORM_BINDINGS) || defined (TEST_SCALEFORM_EVENTS) //----------------------------------------------------------------------------- // Purpose: Helpers for Scaleform events // The following macros and template functions allow Scaleform events to be declared // and broadcast using Panorama-style macros, so a single UI_COMPONENT_BROADCAST_EVENT // macro can broadcast both Panorama and Scaleform events. //----------------------------------------------------------------------------- namespace sfevents { template < typename T > void SetSFParam(KeyValues * pKv, const char* pName) { // Fallback for non-specialized types. pKv->SetInt(pName, 0); } template <> inline void SetSFParam< const char * >(KeyValues * pKv, const char* pName) { pKv->SetString(pName, ""); } template <> inline void SetSFParam< uint8 >(KeyValues * pKv, const char* pName) { pKv->SetInt(pName, 0); } template <> inline void SetSFParam< uint16 >(KeyValues * pKv, const char* pName) { pKv->SetInt(pName, 0); } template <> inline void SetSFParam< uint32 >(KeyValues * pKv, const char* pName) { pKv->SetInt(pName, 0); } template <> inline void SetSFParam< uint64 >(KeyValues * pKv, const char* pName) { pKv->SetUint64(pName, 0); } template <> inline void SetSFParam< int32 >(KeyValues * pKv, const char* pName) { pKv->SetInt(pName, 0); } template <> inline void SetSFParam< int64 >(KeyValues * pKv, const char* pName) { pKv->SetUint64(pName, 0); } template <> inline void SetSFParam< float >(KeyValues * pKv, const char* pName) { pKv->SetFloat(pName, 0.0f); } template <> inline void SetSFParam< bool >(KeyValues * pKv, const char* pName) { pKv->SetBool(pName, false); } template <> inline void SetSFParam< void* >(KeyValues * pKv, const char* pName) { pKv->SetPtr(pName, NULL); } inline void SetSFParamValues(KeyValues * pKv, ...) { va_list args; va_start(args, pKv); FOR_EACH_SUBKEY(pKv, pSubkey) { switch (pSubkey->GetDataType()) { case KeyValues::TYPE_STRING: pKv->SetString(pSubkey->GetName(), va_arg(args, const char*)); break; case KeyValues::TYPE_INT: pKv->SetInt(pSubkey->GetName(), va_arg(args, int)); break; case KeyValues::TYPE_FLOAT: pKv->SetFloat(pSubkey->GetName(), va_arg(args, double)); break; case KeyValues::TYPE_UINT64: pKv->SetUint64(pSubkey->GetName(), va_arg(args, uint64)); break; case KeyValues::TYPE_PTR: pKv->SetPtr(pSubkey->GetName(), va_arg(args, void*)); break; default: Plat_FatalError("Invalid SF Event param type\n"); break; } } } } #define SF_COMPONENT_EVENT_NAME( category, eventname ) "ScaleformComponent_" #category "_" #eventname #define SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ) g_ScaleformComponent_##category##_##eventname##_event #define SF_COMPONENT_DECLARE_EVENT0( category, eventname ) \ class ScaleformComponent_##category##_##eventname##_event \ { public: \ ScaleformComponent_##category##_##eventname##_event() { m_pKv = new KeyValues(SF_COMPONENT_EVENT_NAME(category, eventname)); } \ KeyValues* m_pKv; \ }; \ extern ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_DECLARE_EVENT1( category, eventname, param1_name, param1 ) \ class ScaleformComponent_##category##_##eventname##_event \ { public: \ ScaleformComponent_##category##_##eventname##_event() { \ m_pKv = new KeyValues(SF_COMPONENT_EVENT_NAME(category, eventname)); \ sfevents::SetSFParam(m_pKv, param1_name); \ } \ KeyValues* m_pKv; \ }; \ extern ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_DECLARE_EVENT2(category, eventname, param1_name, param1, param2_name, param2) \ class ScaleformComponent_##category##_##eventname##_event \ { public: \ ScaleformComponent_##category##_##eventname##_event() { \ m_pKv = new KeyValues(SF_COMPONENT_EVENT_NAME(category, eventname)); \ sfevents::SetSFParam(m_pKv, param1_name); \ sfevents::SetSFParam(m_pKv, param2_name); \ } \ KeyValues* m_pKv; \ }; \ extern ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_DECLARE_EVENT3(category, eventname, param1_name, param1, param2_name, param2, param3_name, param3) \ class ScaleformComponent_##category##_##eventname##_event \ { public: \ ScaleformComponent_##category##_##eventname##_event() { \ m_pKv = new KeyValues(SF_COMPONENT_EVENT_NAME(category, eventname)); \ sfevents::SetSFParam(m_pKv, param1_name); \ sfevents::SetSFParam(m_pKv, param2_name); \ sfevents::SetSFParam(m_pKv, param3_name); \ } \ KeyValues* m_pKv; \ }; \ extern ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_DECLARE_EVENT4(category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4) \ class ScaleformComponent_##category##_##eventname##_event \ { public: \ ScaleformComponent_##category##_##eventname##_event() { \ m_pKv = new KeyValues(SF_COMPONENT_EVENT_NAME(category, eventname)); \ sfevents::SetSFParam(m_pKv, param1_name); \ sfevents::SetSFParam(m_pKv, param2_name); \ sfevents::SetSFParam(m_pKv, param3_name); \ sfevents::SetSFParam(m_pKv, param4_name); \ } \ KeyValues* m_pKv; \ }; \ extern ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_DECLARE_EVENT5(category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4, param5_name, param5) \ class ScaleformComponent_##category##_##eventname##_event \ { public: \ ScaleformComponent_##category##_##eventname##_event() { \ m_pKv = new KeyValues(SF_COMPONENT_EVENT_NAME(category, eventname)); \ sfevents::SetSFParam(m_pKv, param1_name); \ sfevents::SetSFParam(m_pKv, param2_name); \ sfevents::SetSFParam(m_pKv, param3_name); \ sfevents::SetSFParam(m_pKv, param4_name); \ sfevents::SetSFParam(m_pKv, param5_name); \ } \ KeyValues* m_pKv; \ }; \ extern ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_DEFINE_EVENT(category, eventname) \ ScaleformComponent_##category##_##eventname##_event SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ); #define SF_COMPONENT_BROADCAST_EVENT( category, eventname, ... ) \ { \ KeyValues* pKv = SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ).m_pKv->MakeCopy(); \ sfevents::SetSFParamValues(pKv, ##__VA_ARGS__); \ if(g_pMatchFramework) g_pMatchFramework->GetEventsSubscription()->BroadcastEvent(pKv); \ } #else // if defined (USE_SCALEFORM_BINDINGS) || defined (TEST_SCALEFORM_EVENTS) #define SF_COMPONENT_EVENT_NAME( category, eventname ) "ScaleformComponent_" #category "_" #eventname #define SF_COMPONENT_EVENT_OBJECT_NAME( category, eventname ) g_ScaleformComponent_##category##_##eventname##_event #define SF_COMPONENT_DECLARE_EVENT0( category, eventname ) #define SF_COMPONENT_DECLARE_EVENT1( category, eventname, param1_name, param1 ) #define SF_COMPONENT_DECLARE_EVENT2(category, eventname, param1_name, param1, param2_name, param2) #define SF_COMPONENT_DECLARE_EVENT3(category, eventname, param1_name, param1, param2_name, param2, param3_name, param3) #define SF_COMPONENT_DECLARE_EVENT4(category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4) #define SF_COMPONENT_DECLARE_EVENT5(category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4, param5_name, param5) #define SF_COMPONENT_DEFINE_EVENT(category, eventname) #define SF_COMPONENT_BROADCAST_EVENT( category, eventname, ... ) #endif // if defined (USE_SCALEFORM_BINDINGS) || defined (TEST_SCALEFORM_EVENTS) #ifdef USE_SCALEFORM_BINDINGS #define SF_COMPONENT_FUNCTION_NAME( fnname ) UiComponentFunction_##fnname // Should match SCALEFORM_CALLBACK_ARGS_DECL in uiscaleform.h #define SF_DEFAULT_PARAMS_DECL IUIMarshalHelper* pui, SFPARAMS obj #define SF_DEFAULT_PARAMS_PASS pui, obj #define SF_COMPONENT_FUNCTION( returntype, fnname ) \ void SF_COMPONENT_FUNCTION_NAME(fnname)( SF_DEFAULT_PARAMS_DECL ) #define SF_COMPONENT_FUNCTION_IMPL( classname, fnname ) \ void classname::SF_COMPONENT_FUNCTION_NAME(fnname)( SF_DEFAULT_PARAMS_DECL ) #define SF_COMPONENT_FUNCTION_DELEGATE( ptrcomponent, fnname ) \ ( ptrcomponent )->SF_COMPONENT_FUNCTION_NAME( fnname )( SF_DEFAULT_PARAMS_PASS ) #define SF_COMPONENT_API_DEF_BEGIN( componentclass ) \ class componentclass##_Table : public IScaleformUIFunctionHandlerDefinitionTable \ { \ public: \ virtual const ScaleformUIFunctionHandlerDefinition* GetTable( void ) const \ { \ static const ScaleformUIFunctionHandlerDefinition fnTable[] = { #define SF_COMPONENT_FUNCTION_API_DEF( returntype, fnname, componentclass ) \ { #fnname, reinterpret_cast( &componentclass::SF_COMPONENT_FUNCTION_NAME( fnname ) ) }, #define SF_COMPONENT_FUNCTION_API_DEF_NOPREFIX( returntype, fnname, componentclass ) \ { #fnname, reinterpret_cast( &componentclass::fnname ) } #define SF_COMPONENT_API_DEF_END( componentclass ) \ { NULL, NULL } \ }; \ return fnTable; \ } \ }; \ static componentclass##_Table g_##componentclass##_Table; \ static SFVALUE g_##componentclass##_SFVALUE[SF_SLOT_IDS_COUNT]; #define SF_COMPONENT_API_INSTALL( iSlot, componentclass, ptrInstance, componentname ) \ do { \ Assert( ( iSlot >= 0 ) && ( iSlot < SF_SLOT_IDS_COUNT ) ); \ g_pScaleformUI->InstallGlobalObject( iSlot, "CScaleformComponent_" #componentname, \ reinterpret_cast(static_cast(ptrInstance)), \ &g_##componentclass##_Table, \ &g_##componentclass##_SFVALUE[iSlot] ); \ } while( 0 ) #define SF_COMPONENT_API_REMOVE( iSlot, componentclass ) \ do { \ Assert( ( iSlot >= 0 ) && ( iSlot < SF_SLOT_IDS_COUNT ) ); \ g_pScaleformUI->RemoveGlobalObject( iSlot, g_##componentclass##_SFVALUE[iSlot] ); g_##componentclass##_SFVALUE[iSlot] = NULL; \ } while( 0 ) #define SF_INTEGRATION_XUID_PARAM( xuidVarName, iParam ) const char * xuidVarName = 0; { \ if ( pui->Params_GetArgType( obj, iParam ) != IUIMarshalHelper::VT_String ) \ { \ AssertMsg( 0, __FUNCTION__ "ActionScript passed a non string param for xuid!\n" ); \ return;\ } \ xuidVarName = ( pui->Params_GetArgAsString( obj, iParam ) ); \ } #define SF_INTEGRATION_ITEMID_PARAM( itemidVarName, iParam ) itemid_t itemidVarName = 0; { \ if ( pui->Params_GetArgType( obj, iParam ) != IUIMarshalHelper::VT_String ) \ { \ AssertMsg( 0, __FUNCTION__ " ActionScript passed a non string param for item id!\n" ); \ return;\ } \ const char *pItemID = ( pui->Params_GetArgAsString( obj, iParam ) ); \ if ( !pItemID ) \ return; \ itemidVarName = (uint64) Q_atoi64( pItemID ) ; \ } #define SF_COMPONENT_NOTIFY_FLASH( category, eventname ) \ if ( FlashAPIIsValid() ) \ { \ WITH_SLOT_LOCKED \ { \ m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, SF_COMPONENT_EVENT_NAME( category, eventname ), NULL, 0 ); \ } \ } #define SF_COMPONENT_FORWARD_EVENT( szEvent ) \ if ( StringHasPrefix( szEvent, "ScaleformComponent_" ) ) \ { \ if ( FlashAPIIsValid() ) \ { \ WITH_SLOT_LOCKED \ { \ m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, szEvent, NULL, 0 ); \ } \ } \ } #define SF_COMPONENT_HOST_DECL() \ public: \ CScaleformComponentHostSupport_ImageCacheHelper m_CScaleformComponentHostSupport_ImageCacheHelper; \ void ScaleformComponentHost_EnsureAvatarCached( SF_DEFAULT_PARAMS_DECL ) \ { \ SF_INTEGRATION_XUID_PARAM( xuidUser, 0 ); \ m_CScaleformComponentHostSupport_ImageCacheHelper.EnsureAvatarCached( xuidUser ); \ } \ void ScaleformComponentHost_EnsureInventoryImageCached( SF_DEFAULT_PARAMS_DECL ) \ { \ SF_INTEGRATION_ITEMID_PARAM( itemID, 0 ); \ m_CScaleformComponentHostSupport_ImageCacheHelper.EnsureInventoryImageCached( itemID ); \ } \ void ScaleformComponentHost_EnsureItemDataImageCached( SF_DEFAULT_PARAMS_DECL ) \ { \ uint16 iDefIndex = ( uint16 ) pui->Params_GetArgAsNumber( obj, 0 ); \ uint16 iPaintIndex = ( uint16 ) pui->Params_GetArgAsNumber( obj, 1 ); \ m_CScaleformComponentHostSupport_ImageCacheHelper.EnsureItemDataImageCached( iDefIndex, iPaintIndex ); \ } \ void ScaleformComponentHost_GetScaleformComponentEventParamString( SF_DEFAULT_PARAMS_DECL ) \ { \ const char *pEventName = ( pui->Params_GetArgAsString( obj, 0 ) ); \ const char *pParamName = ( pui->Params_GetArgAsString( obj, 1 ) ); \ if ( !pEventName || !pParamName ) \ return; \ KeyValues *kvEventData = g_pMatchFramework->GetEventsSubscription()->GetEventData( pEventName ); \ if ( !kvEventData ) \ return; \ pui->Params_SetResult( obj, kvEventData->GetString( pParamName, "" ) ); \ } \ #define SF_COMPONENT_HOST_IMAGE_CACHE_ENABLE( bEnable ) m_CScaleformComponentHostSupport_ImageCacheHelper.EnableCaching( bEnable ) #define SF_COMPONENT_HOST_API_DEF() \ { "EnsureAvatarCached", reinterpret_cast( &T::ScaleformComponentHost_EnsureAvatarCached )}, \ { "EnsureInventoryImageCached", reinterpret_cast( &T::ScaleformComponentHost_EnsureInventoryImageCached )}, \ { "EnsureItemDataImageCached", reinterpret_cast( &T::ScaleformComponentHost_EnsureItemDataImageCached )}, \ { "GetScaleformComponentEventParamString", reinterpret_cast( &T::ScaleformComponentHost_GetScaleformComponentEventParamString )} \ // Registration of GC job handler for scaleform components #define SF_COMPONENT_GC_REG_JOB( gcclientclass, cjobclass, cmsgclass, gcmsgid, ccomponentclass, ccomponentfn ) \ class cjobclass : public GCSDK::CGCClientJob \ { \ public: \ cjobclass( GCSDK::CGCClient *pGCClient ) : GCSDK::CGCClientJob( pGCClient ) { } \ virtual bool BYieldingRunJobFromMsg( GCSDK::IMsgNetPacket *pNetPacket ) \ { \ GCSDK::CProtoBufMsg msg( pNetPacket ); \ ccomponentclass::GetInstance()->ccomponentfn( msg.Body() ); \ return true; \ } \ }; \ GC_REG_CLIENT_JOB( cjobclass, gcmsgid ); inline char const * HelperSfGetStringParamSafe(SF_DEFAULT_PARAMS_DECL, int iParam, char const *szDefault = NULL) { if ((iParam >= 0) && (int(pui->Params_GetNumArgs(obj)) > iParam) && ( pui->Params_GetArgType( obj, iParam ) == IUIMarshalHelper::VT_String ) ) return pui->Params_GetArgAsString(obj, iParam); else return szDefault; } #else // USE_SCALEFORM_BINDINGS #define SF_COMPONENT_FUNCTION_NAME( fnname ) #define SF_DEFAULT_PARAMS_DECL #define SF_DEFAULT_PARAMS_PASS #define SF_COMPONENT_FUNCTION( returntype, fnname ) #define SF_COMPONENT_FUNCTION_IMPL( classname, fnname ) #define SF_COMPONENT_FUNCTION_DELEGATE( ptrcomponent, fnname ) #define SF_COMPONENT_API_DEF_BEGIN( componentclass ) #define SF_COMPONENT_FUNCTION_API_DEF( returntype, fnname, componentclass ) #define SF_COMPONENT_FUNCTION_API_DEF_NOPREFIX( returntype, fnname, componentclass ) #define SF_COMPONENT_API_DEF_END( componentclass ) #define SF_COMPONENT_API_INSTALL( iSlot, componentclass, ptrInstance ) #define SF_COMPONENT_API_REMOVE( iSlot, componentclass ) #define SF_INTEGRATION_XUID_PARAM( xuidVarName, iParam ) #define SF_INTEGRATION_ITEMID_PARAM( itemidVarName, iParam ) #define SF_COMPONENT_NOTIFY_FLASH( category, eventname ) #define SF_COMPONENT_FORWARD_EVENT( szEvent ) #define SF_COMPONENT_HOST_DECL() #define SF_COMPONENT_HOST_IMAGE_CACHE_ENABLE( bEnable ) #define SF_COMPONENT_HOST_API_DEF() #define SF_COMPONENT_GC_REG_JOB( gcclientclass, cjobclass, cmsgclass, gcmsgid, ccomponentclass, ccomponentfn ) #endif // USE_SCALEFORM_BINDINGS #ifdef USE_PANORAMA_BINDINGS #define PANORAMA_COMPONENT_API_DEF_BEGIN( componentclass ) \ void componentclass::JSRegisterFunc() \ { \ #define PANORAMA_COMPONENT_FUNCTION_API_DEF_DOC( returntype, fnname, componentclass, argNames, description ) \ panorama::RegisterJSMethod( #fnname, &componentclass::fnname, description, argNames ); #define PANORAMA_COMPONENT_FUNCTION_API_DEF( returntype, fnname, componentclass ) \ PANORAMA_COMPONENT_FUNCTION_API_DEF_DOC( returntype, fnname, componentclass, "", "" ) #define PANORAMA_COMPONENT_FUNCTION_RAW_API_DEF_DOC( returntype, fnname, componentclass, description ) \ panorama::RegisterJSMethodRaw( #fnname, &componentclass::fnname, description ); #define PANORAMA_COMPONENT_FUNCTION_RAW_API_DEF( returntype, fnname, componentclass ) \ PANORAMA_COMPONENT_FUNCTION_RAW_API_DEF_DOC( returntype, fnname, componentclass, "" ) #define PANORAMA_COMPONENT_API_DEF_END( componentclass ) \ }; \ #define PANORAMA_COMPONENT_API_INSTALL( componentclass, ptrInstance, scriptVarName, description ) \ do { \ panorama::UIEngine()->StartRegisterJSScope( scriptVarName, description ); \ CUtlDelegate< void() > del( ptrInstance, &componentclass::JSRegisterFunc ); \ CUtlAbstractDelegate absDel = del.GetAbstractDelegate(); \ panorama::UIEngine()->ExposeObjectTypeToJavaScript( #componentclass, absDel ); \ panorama::UIEngine()->ExposeGlobalObjectToJavaScript(scriptVarName, ptrInstance, #componentclass, true); \ panorama::UIEngine()->EndRegisterJSScope(); \ } while (0) #define PANORAMA_COMPONENT_API_REMOVE( componentclass ) #define PANORAMA_COMPONENT_EVENT_NAME( category, eventname ) PanoramaComponent_##category##_##eventname #define PANORAMA_COMPONENT_BROADCAST_EVENT( category, eventname, ... ) \ panorama::DispatchEvent(PANORAMA_COMPONENT_EVENT_NAME(category, eventname)(), NULL, ##__VA_ARGS__); #define PANORAMA_COMPONENT_BROADCAST_EVENT_WITH_PARAMS( category, eventname, ... ) \ panorama::DispatchEvent(PANORAMA_COMPONENT_EVENT_NAME(category, eventname)(), NULL, ##__VA_ARGS__); #define PANORAMA_COMPONENT_DECLARE_EVENT0( category, eventname ) \ DECLARE_PANORAMA_EVENT0(PANORAMA_COMPONENT_EVENT_NAME( category, eventname )) #define PANORAMA_COMPONENT_DECLARE_EVENT1( category, eventname, param1 ) \ DECLARE_PANORAMA_EVENT1(PANORAMA_COMPONENT_EVENT_NAME( category, eventname ), param1) #define PANORAMA_COMPONENT_DECLARE_EVENT2(category, eventname, param1, param2) \ DECLARE_PANORAMA_EVENT2(PANORAMA_COMPONENT_EVENT_NAME( category, eventname ), param1, param2) #define PANORAMA_COMPONENT_DECLARE_EVENT3(category, eventname, param1, param2, param3) \ DECLARE_PANORAMA_EVENT3(PANORAMA_COMPONENT_EVENT_NAME( category, eventname ), param1, param2, param3) #define PANORAMA_COMPONENT_DECLARE_EVENT4(category, eventname, param1, param2, param3, param4) \ DECLARE_PANORAMA_EVENT4(PANORAMA_COMPONENT_EVENT_NAME( category, eventname ), param1, param2, param3, param4) #define PANORAMA_COMPONENT_DECLARE_EVENT5(category, eventname, param1, param2, param3, param4, param5) \ DECLARE_PANORAMA_EVENT5(PANORAMA_COMPONENT_EVENT_NAME( category, eventname ), param1, param2, param3, param4, param5) #define PANORAMA_COMPONENT_DEFINE_EVENT(category, eventname)\ DEFINE_PANORAMA_EVENT(PANORAMA_COMPONENT_EVENT_NAME(category, eventname)) #define PANORAMA_COMPONENT_MARSHALL_HELPER_FUNCTION_API_DEF( returntype, fnname, componentclass ) \ RegisterJSMethodWithMarshallHelper( #fnname, &componentclass::SF_COMPONENT_FUNCTION_NAME( fnname ) ); #define PANORAMA_COMPONENT_MARSHALL_HELPER_FUNCTION_API_DEF_NOPREFIX( returntype, fnname, componentclass ) \ RegisterJSMethodWithMarshallHelper( #fnname, &componentclass::fnname ); // Helper class to allow the existing component functions to take a common object for param/return val handling // Allows existing SF component code which expects multiple return types or to sometimes not return a value to remain unchanged and be // called by new panorama js code if needed. class CPanoramaMarshallHelper : public IUIMarshalHelper { public: virtual SFVALUEARRAY Params_GetArgs( SFPARAMS params ) OVERRIDE; virtual unsigned int Params_GetNumArgs( SFPARAMS params ) OVERRIDE; virtual bool Params_ArgIs( SFPARAMS params, unsigned int index, _ValueType v ) OVERRIDE; virtual SFVALUE Params_GetArg( SFPARAMS params, int index = 0 ) OVERRIDE; virtual _ValueType Params_GetArgType( SFPARAMS params, int index = 0 ) OVERRIDE; virtual double Params_GetArgAsNumber( SFPARAMS params, int index = 0 ) OVERRIDE; virtual bool Params_GetArgAsBool( SFPARAMS params, int index = 0 ) OVERRIDE; virtual const char* Params_GetArgAsString( SFPARAMS params, int index = 0 ) OVERRIDE; virtual const wchar_t* Params_GetArgAsStringW( SFPARAMS params, int index = 0 ) OVERRIDE; virtual void Params_DebugSpew( SFPARAMS params ) OVERRIDE; virtual void Params_SetResult( SFPARAMS params, SFVALUE value ) OVERRIDE; virtual void Params_SetResult( SFPARAMS params, int value ) OVERRIDE; virtual void Params_SetResult( SFPARAMS params, float value ) OVERRIDE; virtual void Params_SetResult( SFPARAMS params, bool value ) OVERRIDE; virtual void Params_SetResult( SFPARAMS params, const char* value, bool bMakeNewValue = true ) OVERRIDE; virtual void Params_SetResult( SFPARAMS params, const wchar_t* value, bool bMakeNewValue = true ) OVERRIDE; virtual SFVALUE Params_CreateNewObject( SFPARAMS params ) OVERRIDE; virtual SFVALUE Params_CreateNewString( SFPARAMS params, const char* value ) OVERRIDE; virtual SFVALUE Params_CreateNewString( SFPARAMS params, const wchar_t* value ) OVERRIDE; virtual SFVALUE Params_CreateNewArray( SFPARAMS params, int size = -1 ) OVERRIDE; private: // Scratch storage for returning v8 string params. Grows to high water mark of param count. CUtlVector< CUtlString > m_vecStringStorage; }; CPanoramaMarshallHelper *GetPanoramaMarshallHelper( void ); template< typename ObjType > void JSMethodCallTupleWithMarshallHelper( const v8::FunctionCallbackInfo& args ) { v8::Isolate::Scope isolate_scope( args.GetIsolate() ); v8::HandleScope handle_scope( args.GetIsolate() ); ObjType *pPanel = panorama::GetThisPtrForJSCall( args.Holder() ); if ( !pPanel ) return; v8::Local callbackArray = v8::Local::Cast( args.Data() ); panorama::HACKY_FUNC_PTR_CASTER< void ( ObjType::* )( IUIMarshalHelper* pui, SFPARAMS obj ) > caster; panorama::RestoreFuncPtr( caster, callbackArray, 0 ); ( pPanel->*caster.funcPtr )( GetPanoramaMarshallHelper(), ( SFPARAMS ) &args ); } template < typename ObjType > void RegisterJSMethodWithMarshallHelper( const char *pchMethodName, void ( ObjType::*mf )( IUIMarshalHelper* pui, SFPARAMS obj ), const char *pDesc = NULL ) { v8::Isolate::Scope isolate_scope( panorama::GetV8Isolate() ); v8::HandleScope handle_scope( panorama::GetV8Isolate() ); v8::Handle callbackArray = v8::Array::New( panorama::GetV8Isolate(), V8_CALLBACK_ARRAY_SIZE ); panorama::GetPtrToCallbackArray( mf, callbackArray ); v8::Handle objTemplate = panorama::UIEngine()->GetCurrentV8ObjectTemplateToSetup(); objTemplate->Set( v8::String::NewFromUtf8( panorama::GetV8Isolate(), pchMethodName ), v8::FunctionTemplate::New( panorama::GetV8Isolate(), &JSMethodCallTupleWithMarshallHelper, callbackArray ) ); int nEntry = panorama::UIEngine()->NewRegisterJSEntry( pchMethodName, panorama::RegisterJSEntryInfo_t::k_EMethod, pDesc, panorama::k_ERegisterJSTypeVoid ); panorama::RegisterJSType_t pParamTypes[ 1 ] = { panorama::k_ERegisterJSTypeRawV8Args }; panorama::UIEngine()->SetRegisterJSEntryParams( nEntry, 1, pParamTypes, NULL ); } #else // USE_PANORAMA_BINDINGS #define PANORAMA_COMPONENT_API_DEF_BEGIN( componentclass ) #define PANORAMA_COMPONENT_FUNCTION_API_DEF( returntype, fnname, componentclass ) #define PANORAMA_COMPONENT_FUNCTION_API_DEF_DOC( returntype, fnname, componentclass, argNames, description ) #define PANORAMA_COMPONENT_FUNCTION_RAW_API_DEF( returntype, fnname, componentclass ) #define PANORAMA_COMPONENT_FUNCTION_RAW_API_DEF_DOC( returntype, fnname, componentclass, description ) #define PANORAMA_COMPONENT_API_DEF_END( componentclass ) #define PANORAMA_COMPONENT_API_INSTALL( componentclass, ptrInstance, scriptVarName, description ) #define PANORAMA_COMPONENT_API_REMOVE( componentclass ) #define PANORAMA_COMPONENT_EVENT_NAME( category, eventname ) #define PANORAMA_COMPONENT_BROADCAST_EVENT( category, eventname, ... ) #define PANORAMA_COMPONENT_BROADCAST_EVENT_WITH_PARAMS( category, eventname, ... ) #define PANORAMA_COMPONENT_DECLARE_EVENT0( category, eventname ) #define PANORAMA_COMPONENT_DECLARE_EVENT1( category, eventname, param1 ) #define PANORAMA_COMPONENT_DECLARE_EVENT2(category, eventname, param1, param2) #define PANORAMA_COMPONENT_DECLARE_EVENT3(category, eventname, param1, param2, param3) #define PANORAMA_COMPONENT_DECLARE_EVENT4(category, eventname, param1, param2, param3, param4) #define PANORAMA_COMPONENT_DECLARE_EVENT5(category, eventname, param1, param2, param3, param4, param5) #define PANORAMA_COMPONENT_DEFINE_EVENT(category, eventname) #define PANORAMA_COMPONENT_MARSHALL_HELPER_FUNCTION_API_DEF( returntype, fnname, componentclass ) #define PANORAMA_COMPONENT_MARSHALL_HELPER_FUNCTION_API_DEF_NOPREFIX( returntype, fnname, componentclass ) #endif // USE_PANORAMA_BINDINGS // 7ls - revisit shutdown code #define UI_COMPONENT_API_DEF_COMMON_DOC( componentclass, scriptVarName, description ) \ void componentclass::InstallScaleformBindings(int iSlot) \ { \ SF_COMPONENT_API_INSTALL(iSlot, componentclass, this, scriptVarName); \ } \ void componentclass::InstallPanoramaBindings() \ { \ PANORAMA_COMPONENT_API_INSTALL(componentclass, this, #scriptVarName, description); \ } \ void componentclass::ShutdownComponentApiDef(int iSlot) \ { \ SF_COMPONENT_API_REMOVE(iSlot, componentclass); \ PANORAMA_COMPONENT_API_REMOVE(componentclass); \ } #define UI_COMPONENT_API_DEF_COMMON( componentclass, scriptVarName ) \ UI_COMPONENT_API_DEF_COMMON_DOC( componentclass, scriptVarName, "" ) #define UI_COMPONENT_BROADCAST_EVENT( category, eventname, ... ) \ SF_COMPONENT_BROADCAST_EVENT( category, eventname, ##__VA_ARGS__ ) \ PANORAMA_COMPONENT_BROADCAST_EVENT( category, eventname, ##__VA_ARGS__ ) #define UI_COMPONENT_DECLARE_EVENT0( category, eventname ) \ PANORAMA_COMPONENT_DECLARE_EVENT0( category, eventname ) \ SF_COMPONENT_DECLARE_EVENT0( category, eventname ) #define UI_COMPONENT_DECLARE_EVENT1( category, eventname, param1_name, param1 ) \ PANORAMA_COMPONENT_DECLARE_EVENT1( category, eventname, param1 ) \ SF_COMPONENT_DECLARE_EVENT1( category, eventname, param1_name, param1 ) #define UI_COMPONENT_DECLARE_EVENT2( category, eventname, param1_name, param1, param2_name, param2 ) \ PANORAMA_COMPONENT_DECLARE_EVENT2( category, eventname, param1, param2 ) \ SF_COMPONENT_DECLARE_EVENT2( category, eventname, param1_name, param1, param2_name, param2 ) #define UI_COMPONENT_DECLARE_EVENT3( category, eventname, param1_name, param1, param2_name, param2, param3_name, param3 ) \ PANORAMA_COMPONENT_DECLARE_EVENT3( category, eventname, param1, param2, param3 ) \ SF_COMPONENT_DECLARE_EVENT3( category, eventname, param1_name, param1, param2_name, param2, param3_name, param3 ) #define UI_COMPONENT_DECLARE_EVENT4( category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4 ) \ PANORAMA_COMPONENT_DECLARE_EVENT4( category, eventname, param1, param2, param3, param4 ) \ SF_COMPONENT_DECLARE_EVENT4( category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4 ) #define UI_COMPONENT_DECLARE_EVENT5( category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4, param5_name, param5 ) \ PANORAMA_COMPONENT_DECLARE_EVENT5( category, eventname, param1, param2, param3, param4, param5 ) \ SF_COMPONENT_DECLARE_EVENT5( category, eventname, param1_name, param1, param2_name, param2, param3_name, param3, param4_name, param4, param5_name, param5 ) #define UI_COMPONENT_DEFINE_EVENT( category, eventname )\ PANORAMA_COMPONENT_DEFINE_EVENT( category, eventname )\ SF_COMPONENT_DEFINE_EVENT( category, eventname ) // Only register Panorama cplusplus event handlers if not using Scaleform // (Otherwise handlers will be called twice) #if (defined (USE_PANORAMA_BINDINGS ) && !(defined (USE_SCALEFORM_BINDINGS) || defined (TEST_SCALEFORM_EVENTS))) #define UI_COMPONENT_REGISTER_EVENT_HANDLER(category, eventname, pObj, methodptr) \ RegisterForUnhandledEvent( PANORAMA_COMPONENT_EVENT_NAME(category, eventname)(), pObj, methodptr ); #else #define UI_COMPONENT_REGISTER_EVENT_HANDLER(category, eventname, pObj, methodptr) #endif #define UI_INTEGRATION_XUID_PARAM( xuidVarName, iParam ) XUID xuidVarName = 0; { \ if ( pui->Params_GetArgType( obj, iParam ) != IScaleformUI::VT_String ) \ { \ AssertMsg1( 0, "%s UI code passed a non string param for xuid!\n", __FUNCTION__ ); \ DevMsg( " error: Passed non-string param to %s for param %d.\n", __FUNCTION__, iParam ); \ pui->Params_DebugSpew( obj ); \ return;\ } \ const char *pFriendXuid = ( pui->Params_GetArgAsString( obj, iParam ) ); \ if ( !pFriendXuid ) \ { \ /*AssertMsg( 0, __FUNCTION__ " passed an invalid xuid!\n" );*/ \ } \ CSteamID friendId( (uint64) Q_atoi64( pFriendXuid ) ); \ if ( !friendId.IsValid() || !friendId.BIndividualAccount() ) \ { \ /*AssertMsg( 0, __FUNCTION__ " passed an invalid xuid!\n" );*/ \ xuidVarName = 0; \ } \ else \ { \ xuidVarName = friendId.ConvertToUint64(); \ } \ } // Registration of GC job handler for ui component #define UI_COMPONENT_GC_REG_JOB( gcclientclass, cjobclass, cmsgclass, gcmsgid, ccomponentclass, ccomponentfn ) \ class cjobclass : public GCSDK::CGCClientJob \ { \ public: \ explicit cjobclass( GCSDK::CGCClient *pGCClient ) : GCSDK::CGCClientJob( pGCClient ) { } \ virtual bool BYieldingRunJobFromMsg( GCSDK::IMsgNetPacket *pNetPacket ) \ { \ GCSDK::CProtoBufMsg msg( pNetPacket ); \ ccomponentclass::GetInstance()->ccomponentfn( msg.Body() ); \ return true; \ } \ }; \ GC_REG_CLIENT_JOB( cjobclass, gcmsgid ); // Function decl/impl helpers for ui component code that will be called by scaleform and/or javascript #define UI_COMPONENT_FUNCTION_NAME( fnname ) UiComponentFunction_##fnname #define UI_DEFAULT_PARAMS_DECL IUIMarshalHelper* pui, SFPARAMS obj #define UI_DEFAULT_PARAMS_PASS pui, obj #define UI_COMPONENT_FUNCTION( returntype, fnname ) \ void UI_COMPONENT_FUNCTION_NAME(fnname)( UI_DEFAULT_PARAMS_DECL ) #define UI_COMPONENT_FUNCTION_IMPL( classname, fnname ) \ void classname::UI_COMPONENT_FUNCTION_NAME(fnname)( UI_DEFAULT_PARAMS_DECL ) inline char const * HelperUiGetStringParamSafe( UI_DEFAULT_PARAMS_DECL, int iParam, char const *szDefault = NULL ) { if ( ( iParam >= 0 ) && ( int( pui->Params_GetNumArgs( obj ) ) > iParam ) && ( pui->Params_GetArgType( obj, iParam ) == IScaleformUI::VT_String ) ) return pui->Params_GetArgAsString( obj, iParam ); else return szDefault; } // Convert keyvalues to a json formatted string bool Helper_RecursiveKeyValuesToJSONString( const KeyValues* pKV, CUtlBuffer &outBuffer ); #endif // UICOMPONENT_COMMON_H