我们用一个具体的Slate的例子来分析语法.
首先我们新建个EditorStandaloneWindow类型的插件,命名为PlantMonster,在PlantMonster.cpp中有一个TSharedRef FPlantMonsterModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)的方法.方法中使用了 SNew(SDockTab) 宏. 准备工作结束,下面我们一步一步开始分析.
/**
* Widget authors can use SLATE_BEGIN_ARGS and SLATE_END_ARS to add support
* for widget construction via SNew and SAssignNew.
* e.g.
*
* SLATE_BEGIN_ARGS( SMyWidget )
* , _PreferredWidth( 150.0f )
* , _ForegroundColor( FLinearColor::White )
* {}
*
* SLATE_ATTRIBUTE(float, PreferredWidth)
* SLATE_ATTRIBUTE(FSlateColor, ForegroundColor)
* SLATE_END_ARGS()
*/
#define SLATE_BEGIN_ARGS( SDockTab) \
public: \
struct FArguments : public TSlateBaseNamedArgs<SDockTab> \
{ \
typedef FArguments FArguments; \
FORCENOINLINE FArguments()`
这个宏,在 SDockTab 类中,声明了一个嵌套类(资料:https://blog.csdn.net/Poo_Chai/article/details/91596538 https://blog.csdn.net/liyuanbhu/article/details/43897979 )FArguments,
这个 FArguments 类,继承模板类 TSlateBaseNamedArgs,具体类型后TSlateBaseNamedArgs定义如下
/** Base class for named arguments. Provides settings necessary for all widgets. */
template<typename SDockTab>
struct TSlateBaseNamedArgs
{
TSlateBaseNamedArgs()
: _ToolTipText()
, _ToolTip()
, _Cursor( TOptional<EMouseCursor::Type>() )
, _IsEnabled( true )
, _Visibility( EVisibility::Visible )
, _RenderOpacity(1.0f)
, _ForceVolatile( false )
, _Clipping( EWidgetClipping::Inherit )
, _FlowDirectionPreference( EFlowDirectionPreference::Inherit )
, _RenderTransform( )
, _RenderTransformPivot( FVector2D::ZeroVector )
, _AccessibleParams()
, _AccessibleText()
{
}
/** Used by the named argument pattern as a safe way to 'return *this' for call-chaining purposes. */
SDockTab::FArguments& Me()
{
return *(static_cast<SDockTab::FArguments*>(this));
}
/** Add metadata to this widget. */
SDockTab::FArguments& AddMetaData(TSharedRef<ISlateMetaData> InMetaData)
{
MetaData.Add(InMetaData);
return Me();
}
/** Add metadata to this widget - convenience method - 1 argument */
template<typename MetaDataType, typename Arg0Type>
SDockTab::FArguments& AddMetaData(Arg0Type InArg0)
{
MetaData.Add(MakeShared<MetaDataType>(InArg0));
return Me();
}
/** Add metadata to this widget - convenience method - 2 arguments */
template<typename MetaDataType, typename Arg0Type, typename Arg1Type>
SDockTab::FArguments& AddMetaData(Arg0Type InArg0, Arg1Type InArg1)
{
MetaData.Add(MakeShared<MetaDataType>(InArg0, InArg1));
return Me();
}
SLATE_ATTRIBUTE( FText, ToolTipText )
SLATE_ARGUMENT( TSharedPtr<IToolTip>, ToolTip )
SLATE_ATTRIBUTE( TOptional<EMouseCursor::Type>, Cursor )
SLATE_ATTRIBUTE( bool, IsEnabled )
SLATE_ATTRIBUTE( EVisibility, Visibility )
SLATE_ARGUMENT( float, RenderOpacity )
SLATE_ARGUMENT( bool, ForceVolatile )
SLATE_ARGUMENT( EWidgetClipping, Clipping )
SLATE_ARGUMENT( EFlowDirectionPreference, FlowDirectionPreference)
SLATE_ATTRIBUTE( TOptional<FSlateRenderTransform>, RenderTransform )
SLATE_ATTRIBUTE( FVector2D, RenderTransformPivot )
SLATE_ARGUMENT( FName, Tag )
SLATE_ARGUMENT(TOptional<FAccessibleWidgetData>, AccessibleParams)
SLATE_ATTRIBUTE(FText, AccessibleText)
TArray<TSharedRef<ISlateMetaData>> MetaData;
};
下面分析 TSlateBaseNamedArgs(FArguments的父类) 类中的SLATE_ATTRIBUTE 宏 ,其中一个例子
SLATE_ATTRIBUTE( FText, ToolTipText ) 其宏替换后的结果如下:
/**
* Use this macro to add a attribute to the declaration of your widget.
* An attribute can be a value or a function.
*/
#define SLATE_ATTRIBUTE( FText, ToolTipText ) \
TAttribute< FText > _ToolTipText; \
SDockTab::FArguments& ToolTipText( const TAttribute< FText >& InAttribute ) \
{ \
_ToolTipText = InAttribute; \
return this->Me(); \
} \
\
/* Bind attribute with delegate to a global function
* NOTE: We use a template here to avoid 'typename' issues when hosting attributes inside templated classes */ \
template< typename StaticFuncPtr > \
SDockTab::FArguments& ToolTipText_Static( StaticFuncPtr InFunc ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc ) ); \
return this->Me(); \
} \
template< typename Var1Type > \
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc, Var1Type Var1 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1 ) ); \
return this->Me(); \
} \
template< typename Var1Type, typename Var2Type > \
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_TwoVars< Var1Type, Var2Type >::FFuncPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1, Var2 ) ); \
return this->Me(); \
} \
template< typename Var1Type, typename Var2Type, typename Var3Type > \
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_ThreeVars< Var1Type, Var2Type, Var3Type >::FFuncPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1, Var2, Var3 ) ); \
return this->Me(); \
} \
template< typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_FourVars< Var1Type, Var2Type, Var3Type, Var4Type >::FFuncPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1, Var2, Var3, Var4 ) ); \
return this->Me(); \
} \
\
/* Bind attribute with delegate to a lambda
* technically this works for any functor types, but lambdas are the primary use case */ \
SDockTab::FArguments& ToolTipText_Lambda(TFunction< FText(void) >&& InFunctor) \
{ \
_ToolTipText = TAttribute< FText >::Create(Forward<TFunction< FText(void) >>(InFunctor)); \
return this->Me(); \
} \
\
/* Bind attribute with delegate to a raw C++ class method */ \
template< class UserClass > \
SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_Const< UserClass >::FMethodPtr InFunc ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type > \
SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1, Var2 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1, Var2, Var3 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
SDockTab::FArguments& ToolTipText_Raw( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TRawMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateRaw( InUserObject, InFunc, Var1, Var2, Var3, Var4 ) ); \
return this->Me(); \
} \
\
/* Bind attribute with delegate to a shared pointer-based class method. Slate mostly uses shared pointers so we use an overload for this type of binding. */ \
template< class UserClass > \
SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_Const< UserClass >::FMethodPtr InFunc ) \
{ \
_ToolTipText = TAttribute< FText >( InUserObjectRef, InFunc ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type > \
SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1, Var2 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1, Var2, Var3 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
SDockTab::FArguments& ToolTipText( TSharedRef< UserClass > InUserObjectRef, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObjectRef, InFunc, Var1, Var2, Var3, Var4 ) ); \
return this->Me(); \
} \
\
/* Bind attribute with delegate to a shared pointer-based class method. Slate mostly uses shared pointers so we use an overload for this type of binding. */ \
template< class UserClass > \
SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_Const< UserClass >::FMethodPtr InFunc ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type > \
SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1, Var2 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1, Var2, Var3 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
SDockTab::FArguments& ToolTipText( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TSPMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateSP( InUserObject, InFunc, Var1, Var2, Var3, Var4 ) ); \
return this->Me(); \
} \
\
/* Bind attribute with delegate to a UObject-based class method */ \
template< class UserClass > \
SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_Const< UserClass >::FMethodPtr InFunc ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type > \
SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1, Var2 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3 ) ); \
return this->Me(); \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
SDockTab::FArguments& ToolTipText_UObject( UserClass* InUserObject, typename TAttribute< FText >::FGetter::template TUObjectMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3, Var4 ) ); \
return this->Me(); \
}
所以 SLATE_ATTRIBUTE 宏为 TSlateBaseNamedArgs(FArguments的父类) 类定义了TAttribute< FText >类型的成员变量_ToolTipText以及不同参数类型成员函数ToolTipText_Static
另外要说明一点的是 :在 TAttribute(Attribute.h) 模板类中有 使用了这样一个宏
/**
* Attribute 'getter' delegate
*
* ObjectType GetValue() const
*
* @return The attribute's value
*/
DECLARE_DELEGATE_RetVal( ObjectType, FGetter );
它的定义如下
#define DECLARE_DELEGATE_RetVal( ReturnValueType, DelegateName ) FUNC_DECLARE_DELEGATE( DelegateName, ReturnValueType )
宏 FUNC_DECLARE_DELEGATE 的定义如下
/** Declare the user's delegate object */
// NOTE: The last parameter is variadic and is used as the 'template args' for this delegate's classes (__VA_ARGS__)
#define FUNC_DECLARE_DELEGATE( DelegateName, ... ) \
typedef TBaseDelegate<__VA_ARGS__> DelegateName;
所以 DECLARE_DELEGATE_RetVal( ObjectType, FGetter );宏替换之后就是
typedef TBaseDelegate<ObjectType> FGetter ;
因此 FGetter 就是TBaseDelegate – (TBaseDelegate 的父类为 FDelegateBase),换句话说 FGetter 就是 SDockTab 类中的 FArguments 类中的 TAttribute 类中的 类型为TBaseDelegate 的类名.
有关Delegate的具体实现过程,之后再分析
好,下面继续回到SLATE_ATTRIBUTE宏,在宏 SLATE_ATTRIBUTE( FText, ToolTipText ) 中实现的一个如下函数
template< typename Var1Type > \
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc, Var1Type Var1 ) \
{ \
_ToolTipText = TAttribute< FText >::Create( TAttribute< FText >::FGetter::CreateStatic( InFunc, Var1 ) ); \
return this->Me(); \
} \
其中,TStaticDelegate_OneVar 是 TBaseDelegate 类中的内嵌类,这个TStaticDelegate_OneVar 类的父类为 TBaseStaticDelegateInstance,template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc 中的template表示后边跟着的是一个函数模板指针,
这个函数
SDockTab::FArguments& ToolTipText_Static( typename TAttribute< FText >::FGetter::template TStaticDelegate_OneVar< Var1Type >::FFuncPtr InFunc, Var1Type Var1 )
的功能就是给SDockTab::FArguments的 TAttribute< FText >类型的 _ToolTipText字段初始化
下面分析 SLATE_ARGUMENT 宏 SLATE_ARGUMENT( TSharedPtr, ToolTip ) 宏替换后
/**
* Use this macro to declare a slate argument.
* Arguments differ from attributes in that they can only be values
*/
#define SLATE_ARGUMENT( TSharedPtr<IToolTip>, ToolTip ) \
SharedPtr<IToolTip> _ToolTip; \
FArguments& ToolTip( SharedPtr<IToolTip> InArg ) \
{ \
_ToolTip = InArg; \
return this->Me(); \
}
这个宏的作用就是声明一个SharedPtr类型(共享指针)的字段 _ToolTip,并给出初始化方法
--------------------- 以上是对 FArguments 的父类 TSlateBaseNamedArgs中的宏分析 -----
下面对SDockTab.h中的宏分析
SLATE_DEFAULT_SLOT( FArguments, Content )的定义,宏替换后为
#define SLATE_DEFAULT_SLOT( DeclarationType, SlotName ) \
SLATE_NAMED_SLOT(DeclarationType, SlotName) ; \
DeclarationType & operator[]( const TSharedRef<SWidget> InChild ) \
{ \
_##SlotName.Widget = InChild; \
return *this; \
}
其中 SLATE_NAMED_SLOT 的定义 宏替换后如下
/**
* Use this macro to add support for named slot properties such as Content and Header. See NamedSlotProperty for more details.
*
* NOTE: If you're using this within a widget class that is templated, then you might have to specify a full name for the declaration.
* For example: SLATE_NAMED_SLOT( typename SSuperWidget::Declaration, Content )
*/
#define SLATE_NAMED_SLOT( FArguments, Content ) \
NamedSlotProperty< FArguments > Content() \
{ \
return NamedSlotProperty< FArguments >( *this, _Content ); \
} \
TAlwaysValidWidget _Content; \
所以
宏替换之后 SLATE_DEFAULT_SLOT 如下
#define SLATE_DEFAULT_SLOT( FArguments, Content ) \
NamedSlotProperty< FArguments > Content() \
{ \
return NamedSlotProperty< FArguments >( *this, _Content ); \
} \
TAlwaysValidWidget _Content; \
FArguments & operator[]( const TSharedRef<SWidget> InChild ) \
{ \
_Content.Widget = InChild; \
return *this; \
}
其中 NamedSlotProperty 类的定义 具体类型替换后如下
/**
* We want to be able to do:
* SNew( ContainerWidget )
* .SomeContentArea()
* [
* // Child widgets go here
* ]
*
* NamedSlotProperty is a helper that will be returned by SomeContentArea().
*/
template<class FArguments>
struct NamedSlotProperty
{
NamedSlotProperty( FArguments& InOwnerDeclaration, TAlwaysValidWidget& ContentToSet )
: OwnerDeclaration( InOwnerDeclaration )
, SlotContent(ContentToSet)
{}
FArguments & operator[]( const TSharedRef<SWidget>& InChild )
{
SlotContent.Widget = InChild;
return OwnerDeclaration;
}
FArguments & OwnerDeclaration;
TAlwaysValidWidget & SlotContent;
};
这个 NamedSlotProperty 类重写了操作符[],使之能够添加子widget ,这个类的字段 SlotContent 的类型为 TAlwaysValidWidget 其定义如下
/** A widget reference that is always a valid pointer; defaults to SNullWidget */
struct TAlwaysValidWidget
{
TAlwaysValidWidget()
: Widget(SNullWidget::NullWidget)
{
}
TSharedRef<SWidget> Widget;
};
所以 SLATE_DEFAULT_SLOT( FArguments, Content ) 这个宏的作用就是在
SDockTab类中的FArguments类中定义 了一个返回值类型为 NamedSlotProperty< FArguments > 的方法 Content() , 声明了一个类型为 TAlwaysValidWidget 的字段 _Content, 重写了操作符 [] (注意NamedSlotProperty也重写了操作符[] )
下面分析宏 SLATE_EVENT( FOnTabClosedCallback, OnTabClosed ) (#define SLATE_EVENT( DelegateName, EventName )) 其宏替换后
TabClosedCallback::template TSPMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_TwoVars< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_ThreeVars< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_FourVars< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
FArguments& OnTabClosed( UserClass* InUserObject, typename FOnTabClosedCallback::template TSPMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateSP( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
return *this; \
} \
\
/* Set event delegate to a UObject-based class method */ \
template< class UserClass > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate< UserClass >::FMethodPtr InFunc ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc ); \
return *this; \
} \
template< class UserClass > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_Const< UserClass >::FMethodPtr InFunc ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc ); \
return *this; \
} \
template< class UserClass, typename Var1Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_OneVar< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1 ); \
return *this; \
} \
template< class UserClass, typename Var1Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_OneVar_Const< UserClass, Var1Type >::FMethodPtr InFunc, Var1Type Var1 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_TwoVars< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_TwoVars_Const< UserClass, Var1Type, Var2Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_ThreeVars< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_ThreeVars_Const< UserClass, Var1Type, Var2Type, Var3Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_FourVars< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
return *this; \
} \
template< class UserClass, typename Var1Type, typename Var2Type, typename Var3Type, typename Var4Type > \
FArguments& OnTabClosed_UObject( UserClass* InUserObject, typename FOnTabClosedCallback::template TUObjectMethodDelegate_FourVars_Const< UserClass, Var1Type, Var2Type, Var3Type, Var4Type >::FMethodPtr InFunc, Var1Type Var1, Var2Type Var2, Var3Type Var3, Var4Type Var4 ) \
{ \
_OnTabClosed = FOnTabClosedCallback::CreateUObject( InUserObject, InFunc, Var1, Var2, Var3, Var4 ); \
return *this; \
} \
\
FOnTabClosedCallback _OnTabClosed; \
这个宏 SLATE_EVENT( FOnTabClosedCallback, OnTabClosed ) 的作用就是 声明了一个 FOnTabClosedCallback 类型的字段_OnTabClosed,并给出了一堆初始化它的方法,FOnTabClosedCallback 类型又是由 在SDockableTab.h中的宏 DECLARE_DELEGATE_OneParam(FOnTabClosedCallback, TSharedRef); 生成的 , 又是个Delegate,与FGetter不同的是 :用的是不同参数的TBaseDelegate模板类
最后分析 SLATE_END_ARGS()
#define SLATE_END_ARGS() \
};
就是给 SLATE_BEGIN_ARGS 补全一对{}
-----------------------以上是对 SDockTab.h 中出现的宏的分析-----------------------
下面 我们回到文章的开头 ,我们说在 , 在函数 TSharedRef FPlantMonsterModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs) 中 出现了 SNew(SDockTab) ,
我们对SNew进行分析,SNew 宏替换后为
/**
* Slate widgets are constructed through SNew and SAssignNew.
* e.g.
*
* TSharedRef MyButton = SNew(SButton);
* or
* TSharedPtr MyButton;
* SAssignNew( MyButton, SButton );
*
* Using SNew and SAssignNew ensures that widgets are populated
*/
#define SNew( SDockTab, ... ) \
MakeTDecl<SDockTab>( "SDockTab", __FILE__, __LINE__, RequiredArgs::MakeRequiredArgs(__VA_ARGS__) ) <<= TYPENAME_OUTSIDE_TEMPLATE SDockTab::FArguments()
先说 MakeTDecl(“SDockTab”, FILE, LINE, RequiredArgs::MakeRequiredArgs(VA_ARGS)) 中的参数 RequiredArgs::MakeRequiredArgs(VA_ARGS)
在命名空间RequiredArgs中 定义并实现了不同参数的 MakeRequiredArgs 方法, 返回值也与参数的个数相应 ,SNew(SDockTab)中参数个数为0个 因此 RequiredArgs::MakeRequiredArgs(VA_ARGS) 返回的是一个 RequiredArgs::T0RequiredArgs() 对象
其中 MakeTDecl 的定义 具体类型替换后为
template<typename SDockTab, typename RequiredArgs::T0RequiredArgs>
TDecl<SDockTab, RequiredArgs::T0RequiredArgs> MakeTDecl(const ANSICHAR* InType, const ANSICHAR* InFile, int32 OnLine, RequiredArgs::T0RequiredArgs&& InRequiredArgs)
{
return TDecl<SDockTab, RequiredArgs::T0RequiredArgs>(InType, InFile, OnLine, Forward<RequiredArgs::T0RequiredArgs>(InRequiredArgs));
}
其中 TDecl 的定义 具体类型替换后为
/**
* Utility class used during widget instantiation.
* Performs widget allocation and construction.
* Ensures that debug info is set correctly.
* Returns TSharedRef to widget.
*
* @see SNew
* @see SAssignNew
*/
template<class SDockTab, typename RequiredArgs::T0RequiredArgs>
struct TDecl
{
TDecl( const ANSICHAR* InType, const ANSICHAR* InFile, int32 OnLine, RequiredArgs::T0RequiredArgs&& InRequiredArgs )
: _Widget( TWidgetAllocator<SDockTab, TIsDerivedFrom<SDockTab, SUserWidget>::IsDerived >::PrivateAllocateWidget() )
, _RequiredArgs(InRequiredArgs)
{
_Widget->SetDebugInfo( InType, InFile, OnLine, sizeof(SDockTab) );
}
/**
* Initialize OutVarToInit with the widget that is being constructed.
* @see SAssignNew
*/
template<class ExposeAsSDockTab>
TDecl& Expose( TSharedPtr<ExposeAsSDockTab>& OutVarToInit )
{
OutVarToInit = _Widget;
return *this;
}
/**
* Initialize OutVarToInit with the widget that is being constructed.
* @see SAssignNew
*/
template<class ExposeAsSDockTab>
TDecl& Expose( TSharedRef<ExposeAsSDockTab>& OutVarToInit )
{
OutVarToInit = _Widget;
return *this;
}
/**
* Initialize a WEAK OutVarToInit with the widget that is being constructed.
* @see SAssignNew
*/
template<class ExposeAsSDockTab>
TDecl& Expose( TWeakPtr<ExposeAsSDockTab>& OutVarToInit )
{
OutVarToInit = _Widget;
return *this;
}
/**
* Complete widget construction from InArgs.
*
* @param InArgs NamedArguments from which to construct the widget.
*
* @return A reference to the widget that we constructed.
*/
TSharedRef<SDockTab> operator<<=( const typename SDockTab::FArguments& InArgs ) const
{
//@todo UMG: This should be removed in favor of all widgets calling their superclass construct.
_Widget->SWidgetConstruct(
InArgs._ToolTipText,
InArgs._ToolTip,
InArgs._Cursor,
InArgs._IsEnabled,
InArgs._Visibility,
InArgs._RenderOpacity,
InArgs._RenderTransform,
InArgs._RenderTransformPivot,
InArgs._Tag,
InArgs._ForceVolatile,
InArgs._Clipping,
InArgs._FlowDirectionPreference,
InArgs._AccessibleText.IsSet() ? FAccessibleWidgetData(InArgs._AccessibleText) : InArgs._AccessibleParams,
InArgs.MetaData );
_RequiredArgs.CallConstruct(_Widget, InArgs);
return _Widget;
}
const TSharedRef<SDockTab> _Widget;
RequiredArgs::T0RequiredArgs& _RequiredArgs;
};
在构造函数TDecl中有这样的一个方法 TWidgetAllocator
模板类 TIsDerivedFrom,具体化参数后的定义为
/** Is type DerivedType inherited from SUserWidget. */
template<typename SDockTab, typename SUserWidget>
struct TIsDerivedFrom
{
// Different size types so we can compare their sizes later.
typedef char No[1];
typedef char Yes[2];
// Overloading Test() s.t. only calling it with something that is
// a SUserWidget (or inherited from the SUserWidget) will return a Yes.
static Yes& Test( SUserWidget* );
static Yes& Test( const SUserWidget* );
static No& Test( ... );
// Makes a SDockTab ptr.
static SDockTab* SDockTabPtr(){ return nullptr ;}
public:
// Test the derived type pointer. If it inherits from SUserWidget, the Test( SUserWidget* )
// will be chosen. If it does not, Test( ... ) will be chosen.
static const bool Value = sizeof(Test( SDockTabPtr() )) == sizeof(Yes);
static const bool IsDerived = Value;
};
模板类 TWidgetAllocator,具体化参数后的定义为
/** Normal widgets are allocated directly by the TDecl. */
template<typename SDockTab, bool IsDerived>
struct TWidgetAllocator
{
static TSharedRef<SDockTab> PrivateAllocateWidget()
{
return MakeShared<SDockTab>();
}
};
由上分析 宏 SNew( SDockTab, … ) 可以看成
#define SNew( SDockTab, ... ) \
TDecl<class SDockTab, typename RequiredArgs::T0RequiredArgs>() <<= TYPENAME_OUTSIDE_TEMPLATE SDockTab::FArguments()
TYPENAME_OUTSIDE_TEMPLATE 的定义如下
#if !defined(__clang__) // Clang expects typename outside template
#define TYPENAME_OUTSIDE_TEMPLATE
#endif
C/C++:函数名前引用一个空的宏定义 (https://blog.csdn.net/qq_30015903/article/details/88039320)
最后说操作符重载 <<= ,这个操作符是在 TDecl 类中重载的,具体类型替换后
/**
* Complete widget construction from InArgs.
*
* @param InArgs NamedArguments from which to construct the widget.
*
* @return A reference to the widget that we constructed.
*/
TSharedRef<SDockTab> operator<<=( const typename SDockTab::FArguments& InArgs ) const
{
//@todo UMG: This should be removed in favor of all widgets calling their superclass construct.
_Widget->SWidgetConstruct(
InArgs._ToolTipText,
InArgs._ToolTip,
InArgs._Cursor,
InArgs._IsEnabled,
InArgs._Visibility,
InArgs._RenderOpacity,
InArgs._RenderTransform,
InArgs._RenderTransformPivot,
InArgs._Tag,
InArgs._ForceVolatile,
InArgs._Clipping,
InArgs._FlowDirectionPreference,
InArgs._AccessibleText.IsSet() ? FAccessibleWidgetData(InArgs._AccessibleText) : InArgs._AccessibleParams,
InArgs.MetaData );
_RequiredArgs.CallConstruct(_Widget, InArgs);
return _Widget;
}
所以宏SNew 就是返回一个 初始化后的TSharedRef 共享引用