2022-06-08 13:25:42 -04:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "MVVMViewBlueprintCompiler.h"
# include "MVVMWidgetBlueprintExtension_View.h"
# include "Blueprint/WidgetTree.h"
# include "Bindings/MVVMBindingHelper.h"
# include "Bindings/MVVMCompiledBindingLibraryCompiler.h"
# include "Bindings/MVVMFieldPathHelper.h"
# include "EdGraphSchema_K2.h"
# include "MVVMBlueprintView.h"
# include "MVVMFunctionGraphHelper.h"
# include "MVVMSubsystem.h"
# include "MVVMViewModelBase.h"
# include "WidgetBlueprintCompiler.h"
# include "View/MVVMViewClass.h"
namespace UE : : MVVM : : Private
{
void FMVVMViewBlueprintCompiler : : AddErrorForBinding ( FMVVMBlueprintViewBinding & Binding , const UMVVMBlueprintView * View , const FString & Message ) const
{
2022-06-27 16:24:02 -04:00
const FString BindingName = Binding . GetDisplayNameString ( View ) ;
2022-06-08 13:25:42 -04:00
WidgetBlueprintCompilerContext . MessageLog . Error ( * ( BindingName + TEXT ( " : " ) + Message ) ) ;
Binding . Errors . Add ( FText : : FromString ( BindingName + TEXT ( " : " ) + Message ) ) ;
}
void FMVVMViewBlueprintCompiler : : AddExtension ( UWidgetBlueprintGeneratedClass * Class , UMVVMViewClass * ViewExtension )
{
WidgetBlueprintCompilerContext . AddExtension ( Class , ViewExtension ) ;
}
void FMVVMViewBlueprintCompiler : : CleanOldData ( UWidgetBlueprintGeneratedClass * ClassToClean , UObject * OldCDO )
{
// Clean old View
if ( ! WidgetBlueprintCompilerContext . Blueprint - > bIsRegeneratingOnLoad & & WidgetBlueprintCompilerContext . bIsFullCompile )
{
auto RenameObjectToTransientPackage = [ ] ( UObject * ObjectToRename )
{
const ERenameFlags RenFlags = REN_DontCreateRedirectors | REN_NonTransactional | REN_DoNotDirty ;
ObjectToRename - > Rename ( nullptr , GetTransientPackage ( ) , RenFlags ) ;
ObjectToRename - > SetFlags ( RF_Transient ) ;
ObjectToRename - > ClearFlags ( RF_Public | RF_Standalone | RF_ArchetypeObject ) ;
FLinkerLoad : : InvalidateExport ( ObjectToRename ) ;
} ;
TArray < UObject * > Children ;
const bool bIncludeNestedObjects = false ;
ForEachObjectWithOuter ( ClassToClean , [ & Children ] ( UObject * Child )
{
if ( Cast < UMVVMViewClass > ( Child ) )
{
Children . Add ( Child ) ;
}
} , bIncludeNestedObjects ) ;
for ( UObject * Child : Children )
{
RenameObjectToTransientPackage ( Child ) ;
}
}
}
void FMVVMViewBlueprintCompiler : : CleanTemporaries ( UWidgetBlueprintGeneratedClass * ClassToClean )
{
2022-07-21 14:19:45 -04:00
for ( FCompilerSourceCreatorContext & SourceCreatorContext : CompilerSourceCreatorContexts )
2022-06-08 13:25:42 -04:00
{
if ( SourceCreatorContext . SetterGraph )
{
ensureMsgf ( SourceCreatorContext . SetterGraph - > HasAnyFlags ( RF_Transient ) , TEXT ( " The graph should be temporary and should be generated automaticly. " ) ) ;
// GC may not have clean the graph (GC doesn't run when bRegenerateSkeletonOnly is on)
SourceCreatorContext . SetterGraph - > Rename ( nullptr , SourceCreatorContext . SetterGraph - > GetOuter ( ) , REN_DoNotDirty | REN_ForceNoResetLoaders ) ;
2022-07-13 13:52:41 -04:00
SourceCreatorContext . SetterGraph = nullptr ;
2022-06-08 13:25:42 -04:00
}
}
}
void FMVVMViewBlueprintCompiler : : CreateFunctions ( UMVVMBlueprintView * BlueprintView )
{
if ( ! bAreSourcesCreatorValid | | ! bIsBindingsValid )
{
return ;
}
2022-07-21 14:19:45 -04:00
for ( const FCompilerSourceCreatorContext & SourceCreator : CompilerSourceCreatorContexts )
2022-06-08 13:25:42 -04:00
{
if ( SourceCreator . SetterGraph )
{
if ( ! UE : : MVVM : : FunctionGraphHelper : : GenerateViewModelSetter ( WidgetBlueprintCompilerContext , SourceCreator . SetterGraph , SourceCreator . ViewModelContext . GetViewModelName ( ) ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( TEXT ( " The setter function for '%s' could not be generated. " ) , * SourceCreator . ViewModelContext . GetDisplayName ( ) . ToString ( ) ) ;
continue ;
}
}
}
}
void FMVVMViewBlueprintCompiler : : CreateVariables ( const FWidgetBlueprintCompilerContext : : FCreateVariableContext & Context , UMVVMBlueprintView * BlueprintView )
{
if ( ! BlueprintView )
{
return ;
}
if ( ! bAreSourcesCreatorValid | | ! bAreSourceContextsValid | | ! bIsBindingsValid )
{
return ;
}
if ( Context . GetCompileType ( ) = = EKismetCompileType : : SkeletonOnly )
{
CreateWidgetMap ( Context , BlueprintView ) ;
CreateSourceLists ( Context , BlueprintView ) ;
CreateFunctionsDeclaration ( Context , BlueprintView ) ;
}
auto CreateVariable = [ & Context ] ( const FCompilerSourceContext & SourceContext ) - > FProperty *
{
FEdGraphPinType ViewModelPinType ( UEdGraphSchema_K2 : : PC_Object , NAME_None , SourceContext . Class , EPinContainerType : : None , false , FEdGraphTerminalType ( ) ) ;
FProperty * ViewModelProperty = Context . CreateVariable ( SourceContext . PropertyName , ViewModelPinType ) ;
if ( ViewModelProperty ! = nullptr )
{
ViewModelProperty - > SetPropertyFlags ( CPF_BlueprintVisible | CPF_BlueprintReadOnly | CPF_RepSkip
| CPF_Transient | CPF_DuplicateTransient ) ;
ViewModelProperty - > SetPropertyFlags ( SourceContext . bExposeOnSpawn ? CPF_ExposeOnSpawn : CPF_DisableEditOnInstance ) ;
# if WITH_EDITOR
if ( ! SourceContext . BlueprintSetter . IsEmpty ( ) )
{
ViewModelProperty - > SetMetaData ( FBlueprintMetadata : : MD_PropertySetFunction , * SourceContext . BlueprintSetter ) ;
}
if ( ! SourceContext . DisplayName . IsEmpty ( ) )
{
ViewModelProperty - > SetMetaData ( FBlueprintMetadata : : MD_FunctionCategory , * SourceContext . DisplayName ) ;
}
if ( ! SourceContext . CategoryName . IsEmpty ( ) )
{
ViewModelProperty - > SetMetaData ( FBlueprintMetadata : : MD_FunctionCategory , * SourceContext . CategoryName ) ;
}
if ( SourceContext . bExposeOnSpawn )
{
ViewModelProperty - > SetMetaData ( FBlueprintMetadata : : MD_ExposeOnSpawn , TEXT ( " true " ) ) ;
}
# endif
}
return ViewModelProperty ;
} ;
2022-07-21 14:19:45 -04:00
for ( FCompilerSourceContext & SourceContext : CompilerSourceContexts )
2022-06-08 13:25:42 -04:00
{
SourceContext . Field = BindingHelper : : FindFieldByName ( Context . GetSkeletonGeneratedClass ( ) , FMVVMBindingName ( SourceContext . PropertyName ) ) ;
// The class is not linked yet. It may not be available yet.
if ( SourceContext . Field . IsEmpty ( ) )
{
for ( FField * Field = Context . GetSkeletonGeneratedClass ( ) - > ChildProperties ; Field ! = nullptr ; Field = Field - > Next )
{
if ( Field - > GetFName ( ) = = SourceContext . PropertyName )
{
if ( FProperty * Property = CastField < FProperty > ( Field ) )
{
SourceContext . Field = FMVVMFieldVariant ( Property ) ;
break ;
}
else
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The field for source '%s' exists but is not a property. " )
, * SourceContext . DisplayName ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
}
}
}
// Reuse the property if found
if ( ! SourceContext . Field . IsEmpty ( ) )
{
if ( ! BindingHelper : : IsValidForSourceBinding ( SourceContext . Field ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The field for source '%s' exist but will is not accessible at runtime. " )
, * SourceContext . DisplayName ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
const FProperty * Property = SourceContext . Field . IsProperty ( ) ? SourceContext . Field . GetProperty ( ) : BindingHelper : : GetReturnProperty ( SourceContext . Field . GetFunction ( ) ) ;
const FObjectPropertyBase * ObjectProperty = CastField < const FObjectPropertyBase > ( Property ) ;
const bool bIsCompatible = ObjectProperty & & SourceContext . Class - > IsChildOf ( ObjectProperty - > PropertyClass ) ;
if ( ! bIsCompatible )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( TEXT ( " There is already a property named '%s' that is not compatible with source of the same name. " ) , * SourceContext . DisplayName ) ;
bAreSourceContextsValid = false ;
continue ;
}
}
if ( SourceContext . Field . IsEmpty ( ) )
{
SourceContext . Field = FMVVMConstFieldVariant ( CreateVariable ( SourceContext ) ) ;
}
if ( SourceContext . Field . IsEmpty ( ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( TEXT ( " The variable for '%s' could not be created. " ) , * SourceContext . DisplayName ) ;
bAreSourceContextsValid = false ;
continue ;
}
}
}
void FMVVMViewBlueprintCompiler : : CreateWidgetMap ( const FWidgetBlueprintCompilerContext : : FCreateVariableContext & Context , UMVVMBlueprintView * BlueprintView )
{
// The widget tree is not created yet for SKEL class.
//Context.GetGeneratedClass()->GetWidgetTreeArchetype()
WidgetNameToWidgetPointerMap . Reset ( ) ;
TArray < UWidget * > Widgets ;
UWidgetBlueprint * WidgetBPToScan = Context . GetWidgetBlueprint ( ) ;
while ( WidgetBPToScan ! = nullptr )
{
Widgets = WidgetBPToScan - > GetAllSourceWidgets ( ) ;
if ( Widgets . Num ( ) ! = 0 )
{
break ;
}
WidgetBPToScan = WidgetBPToScan - > ParentClass & & WidgetBPToScan - > ParentClass - > ClassGeneratedBy ? Cast < UWidgetBlueprint > ( WidgetBPToScan - > ParentClass - > ClassGeneratedBy ) : nullptr ;
}
for ( UWidget * Widget : Widgets )
{
WidgetNameToWidgetPointerMap . Add ( Widget - > GetFName ( ) , Widget ) ;
}
}
void FMVVMViewBlueprintCompiler : : CreateSourceLists ( const FWidgetBlueprintCompilerContext : : FCreateVariableContext & Context , UMVVMBlueprintView * BlueprintView )
{
2022-07-21 14:19:45 -04:00
CompilerSourceContexts . Reset ( ) ;
CompilerSourceCreatorContexts . Reset ( ) ;
2022-06-08 13:25:42 -04:00
TSet < FGuid > ViewModelsGuid ;
TSet < FName > WidgetSources ;
for ( const FMVVMBlueprintViewModelContext & ViewModelContext : BlueprintView - > GetViewModels ( ) )
{
if ( ! ViewModelContext . GetViewModelId ( ) . IsValid ( ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( TEXT ( " The viewmodel context has an invalid Guid " ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
if ( ViewModelsGuid . Contains ( ViewModelContext . GetViewModelId ( ) ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' is present twice. " )
, * ViewModelContext . GetViewModelId ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
ViewModelsGuid . Add ( ViewModelContext . GetViewModelId ( ) ) ;
2022-06-29 19:00:59 -04:00
if ( ViewModelContext . GetViewModelClass ( ) = = nullptr | | ! ViewModelContext . IsValid ( ) )
2022-06-08 13:25:42 -04:00
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' has an invalid class. " )
, * ViewModelContext . GetViewModelId ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
const bool bCreateSetterFunction = ViewModelContext . bCreateSetterFunction | | ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : Manual ;
2022-07-13 13:52:41 -04:00
int32 FoundSourceCreatorContextIndex = INDEX_NONE ;
2022-06-08 13:25:42 -04:00
if ( Context . GetCompileType ( ) = = EKismetCompileType : : SkeletonOnly )
{
FCompilerSourceCreatorContext SourceContext ;
SourceContext . ViewModelContext = ViewModelContext ;
SourceContext . Type = ECompilerSourceCreatorType : : ViewModel ;
if ( bCreateSetterFunction )
{
SourceContext . SetterFunctionName = TEXT ( " Set " ) + ViewModelContext . GetViewModelName ( ) . ToString ( ) ;
}
2022-07-21 14:19:45 -04:00
FoundSourceCreatorContextIndex = CompilerSourceCreatorContexts . Emplace ( MoveTemp ( SourceContext ) ) ;
2022-06-08 13:25:42 -04:00
}
else
{
FGuid ViewModelId = ViewModelContext . GetViewModelId ( ) ;
2022-07-21 14:19:45 -04:00
FoundSourceCreatorContextIndex = CompilerSourceCreatorContexts . IndexOfByPredicate ( [ ViewModelId ] ( const FCompilerSourceCreatorContext & Other )
2022-06-08 13:25:42 -04:00
{
return Other . ViewModelContext . GetViewModelId ( ) = = ViewModelId ;
} ) ;
}
2022-07-13 13:52:41 -04:00
checkf ( FoundSourceCreatorContextIndex ! = INDEX_NONE , TEXT ( " The viewmodel was added after the skeleton was created? " ) ) ;
2022-06-08 13:25:42 -04:00
FCompilerSourceContext SourceVariable ;
2022-06-29 19:00:59 -04:00
SourceVariable . Class = ViewModelContext . GetViewModelClass ( ) ;
2022-06-08 13:25:42 -04:00
SourceVariable . PropertyName = ViewModelContext . GetViewModelName ( ) ;
SourceVariable . DisplayName = ViewModelContext . GetDisplayName ( ) . ToString ( ) ;
SourceVariable . CategoryName = TEXT ( " Viewmodel " ) ;
SourceVariable . bExposeOnSpawn = bCreateSetterFunction ;
2022-07-21 14:19:45 -04:00
SourceVariable . BlueprintSetter = CompilerSourceCreatorContexts [ FoundSourceCreatorContextIndex ] . SetterFunctionName ;
CompilerSourceContexts . Emplace ( MoveTemp ( SourceVariable ) ) ;
2022-06-08 13:25:42 -04:00
}
bAreSourceContextsValid = bAreSourcesCreatorValid ;
// Only find the source first property and destination first property.
//The full path will be tested later. We want to build the list of property needed.
for ( int32 Index = 0 ; Index < BlueprintView - > GetNumBindings ( ) ; + + Index )
{
const FMVVMBlueprintViewBinding * BindingPtr = BlueprintView - > GetBindingAt ( Index ) ;
if ( BindingPtr = = nullptr )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding number %d is invalid. " ) , Index ) ) ;
bAreSourceContextsValid = false ;
continue ;
}
const FMVVMBlueprintViewBinding & Binding = * BindingPtr ;
if ( ! Binding . bCompile )
{
continue ;
}
2022-07-13 13:52:41 -04:00
FMVVMViewBlueprintCompiler * Self = this ;
auto GenerateCompilerSourceContext = [ Self , Index , & ViewModelsGuid , & WidgetSources ] ( const UWidgetBlueprintGeneratedClass * Class , const UMVVMBlueprintView * BlueprintView , const FMVVMBlueprintPropertyPath & PropertyPath ) - > bool
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
if ( PropertyPath . IsFromWidget ( ) )
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
if ( PropertyPath . GetWidgetName ( ) . IsNone ( ) )
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
Self - > WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding number %d has an invalid widget name. " ) , Index ) ) ;
return false ;
}
2022-06-08 13:25:42 -04:00
2022-07-13 13:52:41 -04:00
if ( PropertyPath . GetWidgetName ( ) = = Class - > ClassGeneratedBy - > GetFName ( ) )
{
// it's the userwidget
return true ;
}
// If the widget doesn't have a property, add one automatically.
if ( ! WidgetSources . Contains ( PropertyPath . GetWidgetName ( ) ) )
{
WidgetSources . Add ( PropertyPath . GetWidgetName ( ) ) ;
UWidget * * WidgetPtr = Self - > WidgetNameToWidgetPointerMap . Find ( PropertyPath . GetWidgetName ( ) ) ;
2022-06-08 13:25:42 -04:00
if ( WidgetPtr = = nullptr | | * WidgetPtr = = nullptr )
{
2022-07-13 13:52:41 -04:00
Self - > WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding number %d has an invalid path. The widget '%s' could not be found. " ) , Index , * PropertyPath . GetWidgetName ( ) . ToString ( ) ) ) ;
return false ;
2022-06-08 13:25:42 -04:00
}
UWidget * Widget = * WidgetPtr ;
FCompilerSourceContext SourceVariable ;
SourceVariable . Class = Widget - > GetClass ( ) ;
2022-07-13 13:52:41 -04:00
SourceVariable . PropertyName = PropertyPath . GetWidgetName ( ) ;
2022-06-08 13:25:42 -04:00
SourceVariable . DisplayName = Widget - > GetDisplayLabel ( ) ;
SourceVariable . CategoryName = TEXT ( " Widget " ) ;
2022-07-21 14:19:45 -04:00
Self - > CompilerSourceContexts . Emplace ( MoveTemp ( SourceVariable ) ) ;
2022-06-08 13:25:42 -04:00
}
}
2022-07-13 13:52:41 -04:00
else if ( PropertyPath . IsFromViewModel ( ) )
{
const FMVVMBlueprintViewModelContext * SourceViewModelContext = BlueprintView - > FindViewModel ( PropertyPath . GetViewModelId ( ) ) ;
if ( SourceViewModelContext = = nullptr )
{
Self - > WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding number %d has an invalid viewmodel. " ) , Index ) ) ;
return false ;
}
2022-06-08 13:25:42 -04:00
2022-07-13 13:52:41 -04:00
bool bFound = ViewModelsGuid . Contains ( SourceViewModelContext - > GetViewModelId ( ) ) ;
if ( ! bFound )
{
Self - > WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding number %d has a viewmodel that was not added. " ) , Index ) ) ;
return false ;
}
}
else
{
Self - > WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding number %d has a unknown path type. " ) , Index ) ) ;
return false ;
}
return true ;
} ;
if ( IsForwardBinding ( Binding . BindingType ) | | IsBackwardBinding ( Binding . BindingType ) )
{
bAreSourceContextsValid = GenerateCompilerSourceContext ( Context . GetSkeletonGeneratedClass ( ) , BlueprintView , Binding . ViewModelPath )
& & GenerateCompilerSourceContext ( Context . GetSkeletonGeneratedClass ( ) , BlueprintView , Binding . WidgetPath )
& & bAreSourceContextsValid ;
2022-06-08 13:25:42 -04:00
}
}
}
void FMVVMViewBlueprintCompiler : : CreateFunctionsDeclaration ( const FWidgetBlueprintCompilerContext : : FCreateVariableContext & Context , UMVVMBlueprintView * BlueprintView )
{
2022-07-21 14:19:45 -04:00
for ( FCompilerSourceCreatorContext & SourceCreator : CompilerSourceCreatorContexts )
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
if ( ! SourceCreator . SetterFunctionName . IsEmpty ( ) & & SourceCreator . Type = = ECompilerSourceCreatorType : : ViewModel )
2022-06-08 13:25:42 -04:00
{
ensure ( SourceCreator . SetterGraph = = nullptr ) ;
SourceCreator . SetterGraph = UE : : MVVM : : FunctionGraphHelper : : CreateIntermediateFunctionGraph (
WidgetBlueprintCompilerContext
, SourceCreator . SetterFunctionName
, ( FUNC_BlueprintCallable | FUNC_Public )
, TEXT ( " Viewmodel " )
, false ) ;
if ( SourceCreator . SetterGraph = = nullptr | | SourceCreator . SetterGraph - > GetFName ( ) ! = FName ( * SourceCreator . SetterFunctionName ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The setter name %s already exist and could not be autogenerated. " ) , * SourceCreator . SetterFunctionName ) ) ;
}
2022-06-29 19:00:59 -04:00
UE : : MVVM : : FunctionGraphHelper : : AddFunctionArgument ( SourceCreator . SetterGraph , SourceCreator . ViewModelContext . GetViewModelClass ( ) , " Viewmodel " ) ;
2022-06-08 13:25:42 -04:00
}
}
}
bool FMVVMViewBlueprintCompiler : : PreCompile ( UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView )
{
if ( ! bAreSourcesCreatorValid | | ! bAreSourceContextsValid | | ! bIsBindingsValid )
{
return false ;
}
2022-07-13 13:52:41 -04:00
const int32 NumBindings = BlueprintView - > GetNumBindings ( ) ;
2022-07-21 14:19:45 -04:00
CompilerBindings . Reset ( NumBindings * 2 ) ;
2022-07-13 13:52:41 -04:00
BindingSourceContexts . Reset ( NumBindings * 2 ) ;
PreCompileBindingSources ( Class , BlueprintView ) ;
2022-06-08 13:25:42 -04:00
PreCompileSourceCreators ( Class , BlueprintView ) ;
PreCompileBindings ( Class , BlueprintView ) ;
return bAreSourcesCreatorValid & & bAreSourceContextsValid & & bIsBindingsValid ;
}
bool FMVVMViewBlueprintCompiler : : Compile ( UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView , UMVVMViewClass * ViewExtension )
{
if ( ! bAreSourcesCreatorValid | | ! bAreSourceContextsValid | | ! bIsBindingsValid )
{
return false ;
}
TValueOrError < FCompiledBindingLibraryCompiler : : FCompileResult , FString > CompileResult = BindingLibraryCompiler . Compile ( ) ;
if ( CompileResult . HasError ( ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding compilation failed. %s " ) , * CompileResult . GetError ( ) ) ) ;
return false ;
}
CompileSourceCreators ( CompileResult . GetValue ( ) , Class , BlueprintView , ViewExtension ) ;
CompileBindings ( CompileResult . GetValue ( ) , Class , BlueprintView , ViewExtension ) ;
bool bResult = bAreSourcesCreatorValid & & bAreSourceContextsValid & & bIsBindingsValid ;
if ( bResult )
{
ViewExtension - > BindingLibrary = MoveTemp ( CompileResult . GetValue ( ) . Library ) ;
}
return bResult ;
}
2022-07-13 13:52:41 -04:00
bool FMVVMViewBlueprintCompiler : : PreCompileBindingSources ( UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView )
{
const int32 NumBindings = BlueprintView - > GetNumBindings ( ) ;
for ( int32 Index = 0 ; Index < NumBindings ; + + Index )
{
FMVVMBlueprintViewBinding * BindingPtr = BlueprintView - > GetBindingAt ( Index ) ;
if ( BindingPtr = = nullptr )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding at index '%d' is invalid. " ) , Index ) ) ;
bIsBindingsValid = false ;
continue ;
}
FMVVMBlueprintViewBinding & Binding = * BindingPtr ;
if ( ! Binding . bCompile )
{
continue ;
}
if ( IsForwardBinding ( Binding . BindingType ) )
{
const TValueOrError < FBindingSourceContext , FString > CreatedBindingSourceContext = CreateBindingSourceContext ( BlueprintView , Class , Binding . ViewModelPath ) ;
if ( CreatedBindingSourceContext . HasError ( ) )
{
AddErrorForBinding ( Binding , BlueprintView , FString : : Printf ( TEXT ( " The property path '%s' is invalid. %s " )
, * PropertyPathToString ( BlueprintView , Binding . ViewModelPath )
, * CreatedBindingSourceContext . GetError ( ) ) ) ;
bIsBindingsValid = false ;
continue ;
}
FBindingSourceContext BindingSourceContext = CreatedBindingSourceContext . GetValue ( ) ;
if ( ! IsPropertyPathValid ( BindingSourceContext . PropertyPath ) )
{
AddErrorForBinding ( Binding , BlueprintView , FString : : Printf ( TEXT ( " The property path '%s' is invalid. " ) , * PropertyPathToString ( BlueprintView , Binding . ViewModelPath ) ) ) ;
bIsBindingsValid = false ;
continue ;
}
if ( BindingSourceContext . SourceClass = = nullptr )
{
AddErrorForBinding ( Binding , BlueprintView , TEXT ( " Internal error. The binding could not find its source. " ) ) ;
bIsBindingsValid = false ;
continue ;
}
if ( ! BindingSourceContext . bIsRootWidget & & BindingSourceContext . CompilerSourceContextIndex = = INDEX_NONE )
{
AddErrorForBinding ( Binding , BlueprintView , TEXT ( " Internal error. The binding could not find its source. " ) ) ;
bIsBindingsValid = false ;
continue ;
}
BindingSourceContext . BindingIndex = Index ;
BindingSourceContext . bIsForwardBinding = true ;
BindingSourceContexts . Add ( BindingSourceContext ) ;
}
if ( IsBackwardBinding ( Binding . BindingType ) )
{
const TValueOrError < FBindingSourceContext , FString > CreatedBindingSourceContext = CreateBindingSourceContext ( BlueprintView , Class , Binding . WidgetPath ) ;
if ( CreatedBindingSourceContext . HasError ( ) )
{
AddErrorForBinding ( Binding , BlueprintView , FString : : Printf ( TEXT ( " The property path '%s' is invalid. %s " )
, * PropertyPathToString ( BlueprintView , Binding . ViewModelPath )
, * CreatedBindingSourceContext . GetError ( ) ) ) ;
bIsBindingsValid = false ;
continue ;
}
FBindingSourceContext BindingSourceContext = CreatedBindingSourceContext . GetValue ( ) ;
if ( ! IsPropertyPathValid ( BindingSourceContext . PropertyPath ) )
{
AddErrorForBinding ( Binding , BlueprintView , FString : : Printf ( TEXT ( " The property path '%s' is invalid. " ) , * PropertyPathToString ( BlueprintView , Binding . WidgetPath ) ) ) ;
bIsBindingsValid = false ;
continue ;
}
if ( BindingSourceContext . SourceClass = = nullptr )
{
AddErrorForBinding ( Binding , BlueprintView , TEXT ( " Internal error. The binding could not find its source. " ) ) ;
bIsBindingsValid = false ;
continue ;
}
if ( ! BindingSourceContext . bIsRootWidget & & BindingSourceContext . CompilerSourceContextIndex = = INDEX_NONE )
{
AddErrorForBinding ( Binding , BlueprintView , TEXT ( " Internal error. The binding could not find its source. " ) ) ;
bIsBindingsValid = false ;
continue ;
}
BindingSourceContext . BindingIndex = Index ;
BindingSourceContext . bIsForwardBinding = false ;
BindingSourceContexts . Add ( BindingSourceContext ) ;
}
}
return bIsBindingsValid ;
}
2022-06-08 13:25:42 -04:00
bool FMVVMViewBlueprintCompiler : : PreCompileSourceCreators ( UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView )
{
if ( ! bAreSourcesCreatorValid )
{
return false ;
}
2022-07-21 14:19:45 -04:00
for ( FCompilerSourceCreatorContext & SourceCreatorContext : CompilerSourceCreatorContexts )
2022-06-08 13:25:42 -04:00
{
FMVVMViewClass_SourceCreator CompiledSourceCreator ;
if ( SourceCreatorContext . Type = = ECompilerSourceCreatorType : : ViewModel )
{
const FMVVMBlueprintViewModelContext & ViewModelContext = SourceCreatorContext . ViewModelContext ;
2022-07-13 13:52:41 -04:00
checkf ( ViewModelContext . GetViewModelClass ( ) , TEXT ( " The viewmodel class is invalid. It was checked in CreateSourceList " ) ) ;
2022-06-08 13:25:42 -04:00
if ( ViewModelContext . GetViewModelClass ( ) - > HasAllClassFlags ( CLASS_Deprecated ) )
{
2022-07-13 13:52:41 -04:00
WidgetBlueprintCompilerContext . MessageLog . Warning ( * FString : : Printf ( TEXT ( " The viewmodel type '%s' is deprecated and should not be used for '%s'. Please update it in the View Binding panel under Manage ViewModels. " )
2022-06-08 13:25:42 -04:00
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( )
, * ViewModelContext . GetDisplayName ( ) . ToString ( ) ) ) ;
}
if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : Manual )
{
}
else if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : CreateInstance )
{
if ( ViewModelContext . GetViewModelClass ( ) - > HasAllClassFlags ( CLASS_Abstract ) )
{
2022-07-13 13:52:41 -04:00
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel type '%s' is abstract and can't be created for '%s'. You can change it in the View Binding panel under Manage ViewModels. " )
2022-06-08 13:25:42 -04:00
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( )
, * ViewModelContext . GetDisplayName ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
}
else if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : PropertyPath )
{
if ( ViewModelContext . ViewModelPropertyPath . IsEmpty ( ) )
{
2022-07-13 13:52:41 -04:00
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' has an invalid Getter. You can select a new one in the View Binding panel under Manage ViewModels. " )
2022-06-08 13:25:42 -04:00
, * ViewModelContext . GetDisplayName ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = true ;
continue ;
}
// Generate a path to read the value at runtime
2022-07-13 13:52:41 -04:00
TValueOrError < TArray < FMVVMConstFieldVariant > , FString > GeneratedField = FieldPathHelper : : GenerateFieldPathList ( Class , ViewModelContext . ViewModelPropertyPath , true ) ;
if ( GeneratedField . HasError ( ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' (%s) has an invalid Getter. %s " )
, * ViewModelContext . GetDisplayName ( ) . ToString ( )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( )
, * GeneratedField . GetError ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FString > ReadFieldPathResult = BindingLibraryCompiler . AddObjectFieldPath ( GeneratedField . GetValue ( ) , ViewModelContext . GetViewModelClass ( ) , true ) ;
2022-06-08 13:25:42 -04:00
if ( ReadFieldPathResult . HasError ( ) )
{
2022-07-13 13:52:41 -04:00
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' (%s) has an invalid Getter. %s " )
2022-06-08 13:25:42 -04:00
, * ViewModelContext . GetDisplayName ( ) . ToString ( )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( )
, * ReadFieldPathResult . GetError ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
SourceCreatorContext . ReadPropertyPath = ReadFieldPathResult . StealValue ( ) ;
}
else if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : GlobalViewModelCollection )
{
if ( ViewModelContext . GlobalViewModelIdentifier . IsNone ( ) )
{
2022-07-13 13:52:41 -04:00
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' (%s) doesn't have a valid Global identifier. You can specify a new one in the View Binding panel under Manage ViewModels. " )
2022-06-08 13:25:42 -04:00
, * ViewModelContext . GetDisplayName ( ) . ToString ( )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
}
else
{
2022-07-13 13:52:41 -04:00
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' (%s) doesn't have a valid creation type. You can select one in the View Binding panel under Manage ViewModels. " )
2022-06-08 13:25:42 -04:00
, * ViewModelContext . GetDisplayName ( ) . ToString ( )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = true ;
continue ;
}
}
}
return bAreSourcesCreatorValid ;
}
bool FMVVMViewBlueprintCompiler : : CompileSourceCreators ( const FCompiledBindingLibraryCompiler : : FCompileResult & CompileResult , UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView , UMVVMViewClass * ViewExtension )
{
if ( ! bAreSourcesCreatorValid )
{
return false ;
}
2022-07-21 14:19:45 -04:00
for ( const FCompilerSourceCreatorContext & SourceCreatorContext : CompilerSourceCreatorContexts )
2022-06-08 13:25:42 -04:00
{
if ( SourceCreatorContext . Type = = ECompilerSourceCreatorType : : ViewModel )
{
const FMVVMBlueprintViewModelContext & ViewModelContext = SourceCreatorContext . ViewModelContext ;
FMVVMViewClass_SourceCreator CompiledSourceCreator ;
if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : Manual )
{
CompiledSourceCreator = FMVVMViewClass_SourceCreator : : MakeManual ( ViewModelContext . GetViewModelName ( ) , ViewModelContext . GetViewModelClass ( ) ) ;
}
else if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : CreateInstance )
{
CompiledSourceCreator = FMVVMViewClass_SourceCreator : : MakeInstance ( ViewModelContext . GetViewModelName ( ) , ViewModelContext . GetViewModelClass ( ) ) ;
}
else if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : PropertyPath )
{
const FMVVMVCompiledFieldPath * CompiledFieldPath = CompileResult . FieldPaths . Find ( SourceCreatorContext . ReadPropertyPath ) ;
if ( CompiledFieldPath = = nullptr )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' initialization binding was not generated. " )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
2022-07-20 13:37:40 -04:00
CompiledSourceCreator = FMVVMViewClass_SourceCreator : : MakeFieldPath ( ViewModelContext . GetViewModelName ( ) , ViewModelContext . GetViewModelClass ( ) , * CompiledFieldPath , ViewModelContext . bOptional ) ;
2022-06-08 13:25:42 -04:00
}
else if ( ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : GlobalViewModelCollection )
{
if ( ViewModelContext . GlobalViewModelIdentifier . IsNone ( ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' doesn't have a valid Global identifier. " )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
FMVVMViewModelContext GlobalViewModelInstance ;
GlobalViewModelInstance . ContextClass = ViewModelContext . GetViewModelClass ( ) ;
GlobalViewModelInstance . ContextName = ViewModelContext . GlobalViewModelIdentifier ;
if ( ! GlobalViewModelInstance . IsValid ( ) )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The context for viewmodel '%s' could not be created. " )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
2022-07-20 13:37:40 -04:00
CompiledSourceCreator = FMVVMViewClass_SourceCreator : : MakeGlobalContext ( ViewModelContext . GetViewModelName ( ) , MoveTemp ( GlobalViewModelInstance ) , ViewModelContext . bOptional ) ;
2022-06-08 13:25:42 -04:00
}
else
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The viewmodel '%s' doesn't have a valid creation type. " )
, * ViewModelContext . GetViewModelClass ( ) - > GetDisplayNameText ( ) . ToString ( ) ) ) ;
bAreSourcesCreatorValid = false ;
continue ;
}
ViewExtension - > SourceCreators . Add ( MoveTemp ( CompiledSourceCreator ) ) ;
}
}
return bAreSourcesCreatorValid ;
}
bool FMVVMViewBlueprintCompiler : : PreCompileBindings ( UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView )
{
2022-07-13 13:52:41 -04:00
if ( ! bAreSourceContextsValid | | ! bIsBindingsValid )
2022-06-08 13:25:42 -04:00
{
return false ;
}
2022-07-13 13:52:41 -04:00
for ( const FBindingSourceContext & BindingSourceContext : BindingSourceContexts )
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
FMVVMBlueprintViewBinding * BindingPtr = BlueprintView - > GetBindingAt ( BindingSourceContext . BindingIndex ) ;
check ( BindingPtr ) ;
2022-06-08 13:25:42 -04:00
FMVVMBlueprintViewBinding & Binding = * BindingPtr ;
FMVVMViewBlueprintCompiler * Self = this ;
2022-06-27 16:24:02 -04:00
auto AddBinding = [ Self ] ( UWidgetBlueprintGeneratedClass * Class , const TArrayView < TArray < UE : : MVVM : : FMVVMConstFieldVariant > > GetterFields , TArrayView < UE : : MVVM : : FMVVMConstFieldVariant > SetterFields , const UFunction * ConversionFunction ) - > TValueOrError < FCompilerBinding , FString >
2022-06-08 13:25:42 -04:00
{
FCompilerBinding Result ;
for ( const TArray < UE : : MVVM : : FMVVMConstFieldVariant > & GetterField : GetterFields )
{
// Generate a path to read the value at runtime
2022-07-13 13:52:41 -04:00
TValueOrError < TArray < FMVVMConstFieldVariant > , FString > GeneratedField = FieldPathHelper : : GenerateFieldPathList ( GetterField , true ) ;
if ( GeneratedField . HasError ( ) )
{
return MakeError ( FString : : Printf ( TEXT ( " Couldn't create the source field path '%s'. %s " )
, * : : UE : : MVVM : : FieldPathHelper : : ToString ( GetterField )
, * GeneratedField . GetError ( ) ) ) ;
}
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FString > FieldPathResult = Self - > BindingLibraryCompiler . AddFieldPath ( GeneratedField . GetValue ( ) , true ) ;
2022-06-08 13:25:42 -04:00
if ( FieldPathResult . HasError ( ) )
{
return MakeError ( FString : : Printf ( TEXT ( " Couldn't create the source field path '%s'. %s " )
, * : : UE : : MVVM : : FieldPathHelper : : ToString ( GetterField )
, * FieldPathResult . GetError ( ) ) ) ;
}
Result . SourceRead . Add ( FieldPathResult . GetValue ( ) ) ;
}
{
2022-07-13 13:52:41 -04:00
TValueOrError < TArray < FMVVMConstFieldVariant > , FString > GeneratedField = FieldPathHelper : : GenerateFieldPathList ( SetterFields , false ) ;
if ( GeneratedField . HasError ( ) )
{
return MakeError ( FString : : Printf ( TEXT ( " Couldn't create the destination field path '%s'. %s " )
, * : : UE : : MVVM : : FieldPathHelper : : ToString ( SetterFields )
, * GeneratedField . GetError ( ) ) ) ;
}
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FString > FieldPathResult = Self - > BindingLibraryCompiler . AddFieldPath ( GeneratedField . GetValue ( ) , false ) ;
2022-06-08 13:25:42 -04:00
if ( FieldPathResult . HasError ( ) )
{
return MakeError ( FString : : Printf ( TEXT ( " Couldn't create the destination field path '%s'. %s " )
, * : : UE : : MVVM : : FieldPathHelper : : ToString ( SetterFields )
, * FieldPathResult . GetError ( ) ) ) ;
}
Result . DestinationWrite = FieldPathResult . GetValue ( ) ;
}
2022-06-27 16:24:02 -04:00
if ( ConversionFunction ! = nullptr )
2022-06-08 13:25:42 -04:00
{
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldPathHandle , FString > FieldPathResult = Self - > BindingLibraryCompiler . AddConversionFunctionFieldPath ( Class , ConversionFunction ) ;
if ( FieldPathResult . HasError ( ) )
{
return MakeError ( FString : : Printf ( TEXT ( " Couldn't create the conversion function field path '%s'. %s " )
, * ConversionFunction - > GetPathName ( )
, * FieldPathResult . GetError ( ) ) ) ;
}
Result . ConversionFunction = FieldPathResult . GetValue ( ) ;
}
// Generate the binding
TValueOrError < FCompiledBindingLibraryCompiler : : FBindingHandle , FString > BindingResult = Self - > BindingLibraryCompiler . AddBinding ( Result . SourceRead , Result . DestinationWrite , Result . ConversionFunction ) ;
if ( BindingResult . HasError ( ) )
{
return MakeError ( BindingResult . StealError ( ) ) ;
}
Result . BindingHandle = BindingResult . StealValue ( ) ;
return MakeValue ( Result ) ;
} ;
auto AddFieldId = [ Self ] ( UClass * SourceContextClass , bool bNotifyFieldValueChangedRequired , EMVVMBindingMode BindingMode , FName FieldToListenTo ) - > TValueOrError < FCompiledBindingLibraryCompiler : : FFieldIdHandle , FString >
{
if ( ! IsOneTimeBinding ( BindingMode ) & & bNotifyFieldValueChangedRequired )
{
return Self - > BindingLibraryCompiler . AddFieldId ( SourceContextClass , FieldToListenTo ) ;
}
return MakeValue ( FCompiledBindingLibraryCompiler : : FFieldIdHandle ( ) ) ;
} ;
2022-07-13 13:52:41 -04:00
TValueOrError < FCompiledBindingLibraryCompiler : : FFieldIdHandle , FString > AddFieldResult = AddFieldId ( BindingSourceContext . SourceClass , true , Binding . BindingType , BindingSourceContext . FieldId . GetFieldName ( ) ) ;
if ( AddFieldResult . HasError ( ) )
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
AddErrorForBinding ( Binding , BlueprintView , * FString : : Printf ( TEXT ( " The binding could not create its source. %s " ) , * AddFieldResult . GetError ( ) ) ) ;
bIsBindingsValid = false ;
continue ;
2022-06-08 13:25:42 -04:00
}
2022-07-13 13:52:41 -04:00
TArray < TArray < UE : : MVVM : : FMVVMConstFieldVariant > > GetterFields ;
//if (Binding.Conversion.HasConversionFunction && has read values defined (that are not the default one))
//{
// Add the read values for the conversion function
//}
//else
2022-06-08 13:25:42 -04:00
{
2022-07-13 13:52:41 -04:00
GetterFields . Add ( BindingSourceContext . PropertyPath ) ;
2022-06-08 13:25:42 -04:00
}
2022-07-13 13:52:41 -04:00
TArray < UE : : MVVM : : FMVVMConstFieldVariant > SetterPath ;
{
const FMVVMBlueprintPropertyPath & DestinationPath = BindingSourceContext . bIsForwardBinding ? Binding . WidgetPath : Binding . ViewModelPath ;
SetterPath = CreateBindingDestinationPath ( BlueprintView , Class , DestinationPath ) ;
if ( ! IsPropertyPathValid ( SetterPath ) )
{
AddErrorForBinding ( Binding , BlueprintView , FString : : Printf ( TEXT ( " The property path '%s' is invalid. " ) , * PropertyPathToString ( BlueprintView , DestinationPath ) ) ) ;
bIsBindingsValid = false ;
continue ;
}
}
2022-07-21 12:13:57 -04:00
FMemberReference ConversionFunctionReference = BindingSourceContext . bIsForwardBinding ? Binding . Conversion . SourceToDestinationFunction : Binding . Conversion . DestinationToSourceFunction ;
FName ConversionFunctionWrapper = BindingSourceContext . bIsForwardBinding ? Binding . Conversion . SourceToDestinationWrapper : Binding . Conversion . DestinationToSourceWrapper ;
if ( ! ConversionFunctionWrapper . IsNone ( ) )
2022-07-13 13:52:41 -04:00
{
2022-07-21 12:13:57 -04:00
ConversionFunctionReference . SetSelfMember ( ConversionFunctionWrapper ) ;
2022-07-13 13:52:41 -04:00
}
2022-07-21 12:13:57 -04:00
const UFunction * ConversionFunction = ConversionFunctionReference . ResolveMember < UFunction > ( Class ) ;
2022-07-13 13:52:41 -04:00
TValueOrError < FCompilerBinding , FString > AddBindingResult = AddBinding ( Class , GetterFields , SetterPath , ConversionFunction ) ;
if ( AddBindingResult . HasError ( ) )
{
AddErrorForBinding ( Binding , BlueprintView , FString : : Printf ( TEXT ( " The binding could not be created. %s " ) , * AddBindingResult . GetError ( ) ) ) ;
bIsBindingsValid = false ;
continue ;
}
FCompilerBinding NewBinding = AddBindingResult . StealValue ( ) ;
NewBinding . BindingIndex = BindingSourceContext . BindingIndex ;
2022-07-21 14:19:45 -04:00
NewBinding . CompilerSourceContextIndex = BindingSourceContext . CompilerSourceContextIndex ;
2022-07-13 13:52:41 -04:00
NewBinding . FieldIdHandle = AddFieldResult . StealValue ( ) ;
NewBinding . bSourceIsUserWidget = BindingSourceContext . bIsRootWidget ;
NewBinding . bFieldIdNeeded = ! IsOneTimeBinding ( Binding . BindingType ) ;
2022-07-21 14:19:45 -04:00
CompilerBindings . Emplace ( NewBinding ) ;
2022-06-08 13:25:42 -04:00
}
return bIsBindingsValid ;
}
bool FMVVMViewBlueprintCompiler : : CompileBindings ( const FCompiledBindingLibraryCompiler : : FCompileResult & CompileResult , UWidgetBlueprintGeneratedClass * Class , UMVVMBlueprintView * BlueprintView , UMVVMViewClass * ViewExtension )
{
if ( ! bIsBindingsValid )
{
return false ;
}
2022-07-21 14:19:45 -04:00
for ( const FCompilerBinding & CompileBinding : CompilerBindings )
2022-06-08 13:25:42 -04:00
{
const FMVVMBlueprintViewBinding & ViewBinding = * BlueprintView - > GetBindingAt ( CompileBinding . BindingIndex ) ;
FMVVMViewClass_CompiledBinding NewBinding ;
2022-07-21 14:19:45 -04:00
check ( CompileBinding . CompilerSourceContextIndex ! = INDEX_NONE ) ;
NewBinding . SourcePropertyName = CompilerSourceContexts [ CompileBinding . CompilerSourceContextIndex ] . PropertyName ;
2022-06-08 13:25:42 -04:00
const FMVVMVCompiledFieldId * CompiledFieldId = CompileResult . FieldIds . Find ( CompileBinding . FieldIdHandle ) ;
if ( CompiledFieldId = = nullptr & & CompileBinding . bFieldIdNeeded )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The field id for binding '%d' was not generated. " )
, CompileBinding . BindingIndex ) ) ;
bIsBindingsValid = false ;
continue ;
}
const FMVVMVCompiledBinding * CompiledBinding = CompileResult . Bindings . Find ( CompileBinding . BindingHandle ) ;
if ( CompiledBinding = = nullptr )
{
WidgetBlueprintCompilerContext . MessageLog . Error ( * FString : : Printf ( TEXT ( " The binding '%d' was not generated. " )
, CompileBinding . BindingIndex ) ) ;
bIsBindingsValid = false ;
continue ;
}
NewBinding . FieldId = CompiledFieldId ? * CompiledFieldId : FMVVMVCompiledFieldId ( ) ;
NewBinding . Binding = * CompiledBinding ;
NewBinding . UpdateMode = ViewBinding . UpdateMode ;
NewBinding . Flags = 0 ;
NewBinding . Flags | = ( ViewBinding . bEnabled ) ? FMVVMViewClass_CompiledBinding : : EBindingFlags : : EnabledByDefault : 0 ;
NewBinding . Flags | = ( IsForwardBinding ( ViewBinding . BindingType ) ) ? FMVVMViewClass_CompiledBinding : : EBindingFlags : : ForwardBinding : 0 ;
NewBinding . Flags | = ( ViewBinding . BindingType = = EMVVMBindingMode : : TwoWay ) ? FMVVMViewClass_CompiledBinding : : EBindingFlags : : TwoWayBinding : 0 ;
NewBinding . Flags | = ( IsOneTimeBinding ( ViewBinding . BindingType ) ) ? FMVVMViewClass_CompiledBinding : : EBindingFlags : : OneTime : 0 ;
2022-07-21 14:19:45 -04:00
//NewBinding.Flags |= () ? FMVVMViewClass_CompiledBinding::EBindingFlags::RegistrationOptional : 0;
2022-06-08 13:25:42 -04:00
ViewExtension - > CompiledBindings . Emplace ( MoveTemp ( NewBinding ) ) ;
}
return bIsBindingsValid ;
}
const FMVVMViewBlueprintCompiler : : FCompilerSourceCreatorContext * FMVVMViewBlueprintCompiler : : FindViewModelSource ( FGuid Id ) const
{
2022-07-21 14:19:45 -04:00
return CompilerSourceCreatorContexts . FindByPredicate ( [ Id ] ( const FCompilerSourceCreatorContext & Other )
2022-07-13 13:52:41 -04:00
{
return Other . Type = = ECompilerSourceCreatorType : : ViewModel ? Other . ViewModelContext . GetViewModelId ( ) = = Id : false ;
} ) ;
2022-06-08 13:25:42 -04:00
}
2022-07-13 13:52:41 -04:00
TValueOrError < FMVVMViewBlueprintCompiler : : FBindingSourceContext , FString > FMVVMViewBlueprintCompiler : : CreateBindingSourceContext ( const UMVVMBlueprintView * BlueprintView , const UWidgetBlueprintGeneratedClass * Class , const FMVVMBlueprintPropertyPath & PropertyPath )
2022-06-08 13:25:42 -04:00
{
if ( PropertyPath . IsEmpty ( ) )
{
2022-07-13 13:52:41 -04:00
ensureAlways ( false ) ;
return MakeError ( TEXT ( " Empty property path found. This is legal. " ) ) ;
2022-06-08 13:25:42 -04:00
}
2022-07-13 13:52:41 -04:00
FBindingSourceContext Result ;
2022-06-08 13:25:42 -04:00
if ( PropertyPath . IsFromViewModel ( ) )
{
Result . bIsRootWidget = false ;
const FMVVMBlueprintViewModelContext * SourceViewModelContext = BlueprintView - > FindViewModel ( PropertyPath . GetViewModelId ( ) ) ;
check ( SourceViewModelContext ) ;
const FName SourceName = SourceViewModelContext - > GetViewModelName ( ) ;
2022-07-21 14:19:45 -04:00
Result . CompilerSourceContextIndex = CompilerSourceContexts . IndexOfByPredicate ( [ SourceName ] ( const FCompilerSourceContext & Other ) { return Other . PropertyName = = SourceName ; } ) ;
2022-06-08 13:25:42 -04:00
check ( Result . CompilerSourceContextIndex ! = INDEX_NONE ) ;
2022-07-21 14:19:45 -04:00
Result . SourceClass = CompilerSourceContexts [ Result . CompilerSourceContextIndex ] . Class ;
Result . PropertyPath = CreatePropertyPath ( Class , CompilerSourceContexts [ Result . CompilerSourceContextIndex ] . PropertyName , PropertyPath . GetFields ( ) ) ;
2022-06-08 13:25:42 -04:00
}
else if ( PropertyPath . IsFromWidget ( ) )
{
const FName SourceName = PropertyPath . GetWidgetName ( ) ;
Result . bIsRootWidget = SourceName = = Class - > ClassGeneratedBy - > GetFName ( ) ;
if ( Result . bIsRootWidget )
{
Result . CompilerSourceContextIndex = INDEX_NONE ;
Result . SourceClass = Class - > ClassGeneratedBy - > GetClass ( ) ;
Result . PropertyPath = CreatePropertyPath ( Class , FName ( ) , PropertyPath . GetFields ( ) ) ;
}
else
{
2022-07-21 14:19:45 -04:00
Result . CompilerSourceContextIndex = CompilerSourceContexts . IndexOfByPredicate ( [ SourceName ] ( const FCompilerSourceContext & Other ) { return Other . PropertyName = = SourceName ; } ) ;
2022-06-08 13:25:42 -04:00
check ( Result . CompilerSourceContextIndex ! = INDEX_NONE ) ;
2022-07-21 14:19:45 -04:00
Result . SourceClass = CompilerSourceContexts [ Result . CompilerSourceContextIndex ] . Class ;
Result . PropertyPath = CreatePropertyPath ( Class , CompilerSourceContexts [ Result . CompilerSourceContextIndex ] . PropertyName , PropertyPath . GetFields ( ) ) ;
2022-06-08 13:25:42 -04:00
}
}
else
{
ensureAlwaysMsgf ( false , TEXT ( " Not supported yet. " ) ) ;
}
2022-07-13 13:52:41 -04:00
// The path may contains another INotifyFieldValueChanged
TValueOrError < FieldPathHelper : : FParsedBindingInfo , FString > BindingInfoResult = FieldPathHelper : : GetBindingInfoFromFieldPath ( Class , Result . PropertyPath ) ;
if ( BindingInfoResult . HasError ( ) )
{
return MakeError ( BindingInfoResult . StealError ( ) ) ;
}
const FieldPathHelper : : FParsedBindingInfo & BindingInfo = BindingInfoResult . GetValue ( ) ;
Result . FieldId = BindingInfo . NotifyFieldId ;
const bool bCreateADynamicSourceEntry = BindingInfo . ViewModelIndex > 1
& & BindingInfo . NotifyFieldClass ! = nullptr ;
// The INotifyFieldValueChanged/viewmodel is not the fist property. Creates the ViaBinding source entries.
if ( bCreateADynamicSourceEntry )
{
Result . SourceClass = BindingInfo . NotifyFieldClass ;
Result . CompilerSourceContextIndex = INDEX_NONE ;
Result . bIsRootWidget = false ;
FString InterfacePath = FieldPathHelper : : ToString ( BindingInfo . NotifyFieldInterfacePath ) ;
2022-07-21 14:19:45 -04:00
int32 SourceCreatorContextIndex = CompilerSourceCreatorContexts . IndexOfByPredicate ( [ & InterfacePath ] ( const FCompilerSourceCreatorContext & Other )
2022-07-13 13:52:41 -04:00
{
return ( Other . Type = = ECompilerSourceCreatorType : : ViewModel )
? ( Other . ViewModelContext . CreationType = = EMVVMBlueprintViewModelContextCreationType : : PropertyPath
& & Other . ViewModelContext . ViewModelPropertyPath = = InterfacePath )
: false ;
} ) ;
// Add if the path doesn't already exists
2022-07-21 14:19:45 -04:00
if ( ! CompilerSourceCreatorContexts . IsValidIndex ( SourceCreatorContextIndex ) )
2022-07-13 13:52:41 -04:00
{
return MakeError ( TEXT ( " The field in the path is from a viewmodel that is not the root of the path. This is not yet supported. " ) ) ;
}
Result . PropertyPath . RemoveAt ( 0 , BindingInfo . ViewModelIndex ) ;
2022-07-21 14:19:45 -04:00
if ( CompilerSourceCreatorContexts [ SourceCreatorContextIndex ] . Type = = ECompilerSourceCreatorType : : ViewModel )
2022-07-13 13:52:41 -04:00
{
Result . CompilerSourceContextIndex = SourceCreatorContextIndex ;
}
}
else
{
if ( Result . SourceClass ! = BindingInfo . NotifyFieldClass )
{
return MakeError ( TEXT ( " Internal Error. The class doesn't match " ) ) ;
}
}
return MakeValue ( Result ) ;
2022-06-08 13:25:42 -04:00
}
TArray < FMVVMConstFieldVariant > FMVVMViewBlueprintCompiler : : CreateBindingDestinationPath ( const UMVVMBlueprintView * BlueprintView , const UWidgetBlueprintGeneratedClass * Class , const FMVVMBlueprintPropertyPath & PropertyPath ) const
{
if ( PropertyPath . IsEmpty ( ) )
{
2022-07-13 13:52:41 -04:00
ensureAlwaysMsgf ( false , TEXT ( " Empty property path found. This is legal. " ) ) ;
2022-06-08 13:25:42 -04:00
return TArray < FMVVMConstFieldVariant > ( ) ;
}
if ( PropertyPath . IsFromViewModel ( ) )
{
const FMVVMBlueprintViewModelContext * SourceViewModelContext = BlueprintView - > FindViewModel ( PropertyPath . GetViewModelId ( ) ) ;
check ( SourceViewModelContext ) ;
FName DestinationName = SourceViewModelContext - > GetViewModelName ( ) ;
2022-07-21 14:19:45 -04:00
const int32 DestinationVariableContextIndex = CompilerSourceContexts . IndexOfByPredicate ( [ DestinationName ] ( const FCompilerSourceContext & Other ) { return Other . PropertyName = = DestinationName ; } ) ;
2022-06-08 13:25:42 -04:00
check ( DestinationVariableContextIndex ! = INDEX_NONE ) ;
2022-07-21 14:19:45 -04:00
return CreatePropertyPath ( Class , CompilerSourceContexts [ DestinationVariableContextIndex ] . PropertyName , PropertyPath . GetFields ( ) ) ;
2022-06-08 13:25:42 -04:00
}
else if ( PropertyPath . IsFromWidget ( ) )
{
FName DestinationName = PropertyPath . GetWidgetName ( ) ;
checkf ( ! DestinationName . IsNone ( ) , TEXT ( " The destination should have been checked and set bAreSourceContextsValid. " ) ) ;
const bool bSourceIsUserWidget = DestinationName = = Class - > ClassGeneratedBy - > GetFName ( ) ;
if ( bSourceIsUserWidget )
{
return CreatePropertyPath ( Class , FName ( ) , PropertyPath . GetFields ( ) ) ;
}
else
{
2022-07-21 14:19:45 -04:00
const int32 DestinationVariableContextIndex = CompilerSourceContexts . IndexOfByPredicate ( [ DestinationName ] ( const FCompilerSourceContext & Other ) { return Other . PropertyName = = DestinationName ; } ) ;
2022-06-08 13:25:42 -04:00
check ( DestinationVariableContextIndex ! = INDEX_NONE ) ;
2022-07-21 14:19:45 -04:00
return CreatePropertyPath ( Class , CompilerSourceContexts [ DestinationVariableContextIndex ] . PropertyName , PropertyPath . GetFields ( ) ) ;
2022-06-08 13:25:42 -04:00
}
}
else
{
ensureAlwaysMsgf ( false , TEXT ( " Not supported yet. " ) ) ;
return CreatePropertyPath ( Class , FName ( ) , PropertyPath . GetFields ( ) ) ;
}
}
FString FMVVMViewBlueprintCompiler : : PropertyPathToString ( const UMVVMBlueprintView * BlueprintView , const FMVVMBlueprintPropertyPath & PropertyPath ) const
{
if ( PropertyPath . IsEmpty ( ) )
{
return FString ( ) ;
}
TStringBuilder < 512 > Result ;
if ( PropertyPath . IsFromViewModel ( ) )
{
if ( const FMVVMBlueprintViewModelContext * SourceViewModelContext = BlueprintView - > FindViewModel ( PropertyPath . GetViewModelId ( ) ) )
{
Result < < SourceViewModelContext - > GetViewModelName ( ) ;
}
else
{
Result < < TEXT ( " <none> " ) ;
}
}
else if ( PropertyPath . IsFromWidget ( ) )
{
Result < < PropertyPath . GetWidgetName ( ) ;
}
else
{
Result < < TEXT ( " <none> " ) ;
}
FString BasePropertyPath = PropertyPath . GetBasePropertyPath ( ) ;
if ( BasePropertyPath . Len ( ) )
{
Result < < TEXT ( ' . ' ) ;
Result < < MoveTemp ( BasePropertyPath ) ;
}
return Result . ToString ( ) ;
}
TArray < FMVVMConstFieldVariant > FMVVMViewBlueprintCompiler : : CreatePropertyPath ( const UClass * Class , FName PropertyName , TArray < FMVVMConstFieldVariant > Properties ) const
{
if ( PropertyName . IsNone ( ) )
{
return Properties ;
}
check ( Class ) ;
FMVVMConstFieldVariant NewProperty = BindingHelper : : FindFieldByName ( Class , FMVVMBindingName ( PropertyName ) ) ;
Properties . Insert ( NewProperty , 0 ) ;
return Properties ;
}
bool FMVVMViewBlueprintCompiler : : IsPropertyPathValid ( TArrayView < const FMVVMConstFieldVariant > PropertyPath ) const
{
for ( const FMVVMConstFieldVariant & Field : PropertyPath )
{
if ( Field . IsEmpty ( ) )
{
return false ;
}
if ( Field . IsProperty ( ) & & Field . GetProperty ( ) = = nullptr )
{
return false ;
}
if ( Field . IsFunction ( ) & & Field . GetFunction ( ) = = nullptr )
{
return false ;
}
}
return true ;
}
} //namespace