bool FStructureEditorUtils::AddVariable(UBlueprint* Blueprint, FName StructName, const FEdGraphPinType& VarType) { if (NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("AddVariable", "Add Variable") ); Blueprint->Modify(); FBPStructureDescription* StructureDesc = Blueprint->UserDefinedStructures.FindByPredicate(FFindByNameHelper(StructName)); if (StructureDesc) { FString ErrorMessage; if (!CanHaveAMemberVariableOfType(StructureDesc->CompiledStruct, VarType, &ErrorMessage)) { UE_LOG(LogBlueprint, Warning, TEXT("%s"), *ErrorMessage); return false; } const FName VarName = FMemberVariableNameHelper::Generate(StructureDesc->CompiledStruct, FString()); check(NULL == StructureDesc->Fields.FindByPredicate(FFindByNameHelper(VarName))); const FString DisplayName = VarName.ToString(); check(IsUniqueVariableDisplayName(Blueprint, StructName, DisplayName)); FBPVariableDescription NewVar; NewVar.VarName = VarName; NewVar.FriendlyName = DisplayName; NewVar.VarType = VarType; NewVar.VarGuid = FGuid::NewGuid(); StructureDesc->Fields.Add(NewVar); OnStructureChanged(*StructureDesc, Blueprint); return true; } } return false; }
bool FStructureEditorUtils::ChangeVariableType(UUserDefinedStruct* Struct, FGuid VarGuid, const FEdGraphPinType& NewType) { if (Struct) { FString ErrorMessage; if(!CanHaveAMemberVariableOfType(Struct, NewType, &ErrorMessage)) { UE_LOG(LogBlueprint, Warning, TEXT("%s"), *ErrorMessage); return false; } auto VarDesc = GetVarDescByGuid(Struct, VarGuid); if(VarDesc) { const bool bChangedType = (VarDesc->ToPinType() != NewType); if (bChangedType) { const FScopedTransaction Transaction(LOCTEXT("ChangeVariableType", "Change Variable Type")); ModifyStructData(Struct); VarDesc->VarName = FMemberVariableNameHelper::Generate(Struct, VarDesc->FriendlyName, VarDesc->VarGuid); VarDesc->DefaultValue = FString(); VarDesc->SetPinType(NewType); OnStructureChanged(Struct); return true; } } } return false; }
bool FStructureEditorUtils::RenameVariable(UUserDefinedStruct* Struct, FGuid VarGuid, const FString& NewDisplayNameStr) { if (Struct) { auto VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc && !NewDisplayNameStr.IsEmpty() && FName(*NewDisplayNameStr).IsValidXName(INVALID_OBJECTNAME_CHARACTERS) && IsUniqueVariableDisplayName(Struct, NewDisplayNameStr)) { const FScopedTransaction Transaction(LOCTEXT("RenameVariable", "Rename Variable")); ModifyStructData(Struct); VarDesc->FriendlyName = NewDisplayNameStr; //>>> TEMPORARY it's more important to prevent changes in structs instances, than to have consistent names if (GetGuidFromPropertyName(VarDesc->VarName).IsValid()) //<<< TEMPORARY { const FName NewName = FMemberVariableNameHelper::Generate(Struct, NewDisplayNameStr, VarGuid); check(NULL == GetVarDesc(Struct).FindByPredicate(FFindByNameHelper<FStructVariableDescription>(NewName))) VarDesc->VarName = NewName; } OnStructureChanged(Struct); return true; } } return false; }
bool FStructureEditorUtils::RemoveVariable(UUserDefinedStruct* Struct, FGuid VarGuid) { if(Struct) { const auto OldNum = GetVarDesc(Struct).Num(); const bool bAllowToMakeEmpty = false; if (bAllowToMakeEmpty || (OldNum > 1)) { const FScopedTransaction Transaction(LOCTEXT("RemoveVariable", "Remove Variable")); ModifyStructData(Struct); GetVarDesc(Struct).RemoveAll(FFindByGuidHelper<FStructVariableDescription>(VarGuid)); if (OldNum != GetVarDesc(Struct).Num()) { OnStructureChanged(Struct); return true; } } else { UE_LOG(LogBlueprint, Log, TEXT("Member variable cannot be removed. User Defined Structure cannot be empty")); } } return false; }
bool FStructureEditorUtils::AddVariable(UUserDefinedStruct* Struct, const FEdGraphPinType& VarType) { if (Struct) { const FScopedTransaction Transaction( LOCTEXT("AddVariable", "Add Variable") ); ModifyStructData(Struct); FString ErrorMessage; if (!CanHaveAMemberVariableOfType(Struct, VarType, &ErrorMessage)) { UE_LOG(LogBlueprint, Warning, TEXT("%s"), *ErrorMessage); return false; } const FGuid Guid = FGuid::NewGuid(); FString DisplayName; const FName VarName = FMemberVariableNameHelper::Generate(Struct, FString(), Guid, &DisplayName); check(NULL == GetVarDesc(Struct).FindByPredicate(FStructureEditorUtils::FFindByNameHelper<FStructVariableDescription>(VarName))); check(IsUniqueVariableDisplayName(Struct, DisplayName)); FStructVariableDescription NewVar; NewVar.VarName = VarName; NewVar.FriendlyName = DisplayName; NewVar.SetPinType(VarType); NewVar.VarGuid = Guid; NewVar.bDontEditoOnInstance = false; NewVar.bInvalidMember = false; GetVarDesc(Struct).Add(NewVar); OnStructureChanged(Struct); return true; } return false; }
bool FStructureEditorUtils::ChangeMultiLineTextEnabled(UUserDefinedStruct* Struct, FGuid VarGuid, bool bIsEnabled) { auto VarDesc = GetVarDescByGuid(Struct, VarGuid); if (CanEnableMultiLineText(Struct, VarGuid) && VarDesc->bEnableMultiLineText != bIsEnabled) { const FScopedTransaction Transaction(LOCTEXT("ChangeMultiLineTextEnabled", "Change Multi-line Text Enabled")); ModifyStructData(Struct); VarDesc->bEnableMultiLineText = bIsEnabled; auto Property = FindField<UProperty>(Struct, VarDesc->VarName); if (Property) { if (VarDesc->bEnableMultiLineText) { Property->SetMetaData("MultiLine", TEXT("true")); } else { Property->RemoveMetaData("MultiLine"); } } OnStructureChanged(Struct); return true; } return false; }
bool FStructureEditorUtils::ChangeVariableDefaultValue(UBlueprint* Blueprint, FName StructName, FGuid VarGuid, const FString& NewDefaultValue) { if(NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("ChangeVariableDefaultValue", "Change Variable Default Value") ); Blueprint->Modify(); FBPStructureDescription* StructureDesc = Blueprint->UserDefinedStructures.FindByPredicate(FFindByNameHelper(StructName)); if (StructureDesc) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); FBPVariableDescription* VarDesc = StructureDesc->Fields.FindByPredicate(FFindByGuidHelper(VarGuid)); if (VarDesc && (NewDefaultValue != VarDesc->DefaultValue) && K2Schema->DefaultValueSimpleValidation(VarDesc->VarType, FString(), NewDefaultValue, NULL, FText::GetEmpty())) { VarDesc->DefaultValue = NewDefaultValue; OnStructureChanged(*StructureDesc, Blueprint); return true; } } } return false; }
bool FStructureEditorUtils::ChangeVariableType(UBlueprint* Blueprint, FName StructName, FGuid VarGuid, const FEdGraphPinType& NewType) { if(NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("ChangeVariableType", "Change Variable Type") ); Blueprint->Modify(); FBPStructureDescription* StructureDesc = Blueprint->UserDefinedStructures.FindByPredicate(FFindByNameHelper(StructName)); if(StructureDesc) { FString ErrorMessage; if(!CanHaveAMemberVariableOfType(StructureDesc->CompiledStruct, NewType, &ErrorMessage)) { UE_LOG(LogBlueprint, Warning, TEXT("%s"), *ErrorMessage); return false; } FBPVariableDescription* VarDesc = StructureDesc->Fields.FindByPredicate(FFindByGuidHelper(VarGuid)); if(VarDesc && (NewType != VarDesc->VarType)) { VarDesc->VarName = FMemberVariableNameHelper::Generate(StructureDesc->CompiledStruct, VarDesc->FriendlyName); VarDesc->DefaultValue = FString(); VarDesc->VarType = NewType; OnStructureChanged(*StructureDesc, Blueprint); return true; } } } return false; }
bool FStructureEditorUtils::RenameVariable(UBlueprint* Blueprint, FName StructName, FGuid VarGuid, const FString& NewDisplayNameStr) { if (NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("RenameVariable", "Rename Variable") ); Blueprint->Modify(); FBPStructureDescription* StructureDesc = Blueprint->UserDefinedStructures.FindByPredicate(FFindByNameHelper(StructName)); if (StructureDesc) { const FName NewNameBase(*NewDisplayNameStr); if (NewNameBase.IsValidXName(INVALID_OBJECTNAME_CHARACTERS) && IsUniqueVariableDisplayName(Blueprint, StructName, NewDisplayNameStr)) { const FName NewName = FMemberVariableNameHelper::Generate(StructureDesc->CompiledStruct, NewDisplayNameStr); if (NULL == StructureDesc->Fields.FindByPredicate(FFindByNameHelper(NewName))) { FBPVariableDescription* VarDesc = StructureDesc->Fields.FindByPredicate(FFindByGuidHelper(VarGuid)); if (VarDesc) { VarDesc->FriendlyName = NewDisplayNameStr; VarDesc->VarName = NewName; OnStructureChanged(*StructureDesc, Blueprint); return true; } } } } } return false; }
bool FStructureEditorUtils::ChangeVariableDefaultValue(UUserDefinedStruct* Struct, FGuid VarGuid, const FString& NewDefaultValue) { auto ValidateDefaultValue = [](const FStructVariableDescription& VarDesc, const FString& InNewDefaultValue) -> bool { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); const FEdGraphPinType PinType = VarDesc.ToPinType(); bool bResult = false; //TODO: validation for values, that are not passed by string if (PinType.PinCategory == K2Schema->PC_Text) { bResult = true; } else if ((PinType.PinCategory == K2Schema->PC_Object) || (PinType.PinCategory == K2Schema->PC_Interface) || (PinType.PinCategory == K2Schema->PC_Class) || (PinType.PinCategory == K2Schema->PC_AssetClass) || (PinType.PinCategory == K2Schema->PC_Asset)) { // K2Schema->DefaultValueSimpleValidation finds an object, passed by path, invalid bResult = true; } else { bResult = K2Schema->DefaultValueSimpleValidation(PinType, FString(), InNewDefaultValue, NULL, FText::GetEmpty()); } return bResult; }; auto VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc && (NewDefaultValue != VarDesc->DefaultValue) && ValidateDefaultValue(*VarDesc, NewDefaultValue)) { bool bAdvancedValidation = true; if (!NewDefaultValue.IsEmpty()) { const auto Property = FindField<UProperty>(Struct, VarDesc->VarName); FStructOnScope StructDefaultMem(Struct); bAdvancedValidation = StructDefaultMem.IsValid() && Property && FBlueprintEditorUtils::PropertyValueFromString(Property, NewDefaultValue, StructDefaultMem.GetStructMemory()); } if (bAdvancedValidation) { const FScopedTransaction Transaction(LOCTEXT("ChangeVariableDefaultValue", "Change Variable Default Value")); TGuardValue<FStructureEditorUtils::EStructureEditorChangeInfo> ActiveChangeGuard(FStructureEditorUtils::FStructEditorManager::ActiveChange, EStructureEditorChangeInfo::DefaultValueChanged); ModifyStructData(Struct); VarDesc->DefaultValue = NewDefaultValue; OnStructureChanged(Struct, EStructureEditorChangeInfo::DefaultValueChanged); return true; } } return false; }
bool FStructureEditorUtils::ChangeEditableOnBPInstance(UUserDefinedStruct* Struct, FGuid VarGuid, bool bInIsEditable) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); auto VarDesc = GetVarDescByGuid(Struct, VarGuid); const bool bNewDontEditoOnInstance = !bInIsEditable; if (VarDesc && (bNewDontEditoOnInstance != VarDesc->bDontEditoOnInstance)) { const FScopedTransaction Transaction(LOCTEXT("ChangeVariableOnBPInstance", "Change variable editable on BP instance")); ModifyStructData(Struct); VarDesc->bDontEditoOnInstance = bNewDontEditoOnInstance; OnStructureChanged(Struct); return true; } return false; }
bool FStructureEditorUtils::AddStructure(UBlueprint* Blueprint) { if(NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("AddStructure", "Add Structure") ); Blueprint->Modify(); const FName StructName = MakeUniqueStructName(Blueprint, TEXT("NewStruct")); FBPStructureDescription StructureDesc; StructureDesc.Name = StructName; Blueprint->UserDefinedStructures.Add(StructureDesc); OnStructureChanged(StructureDesc, Blueprint); return true; } return false; }
bool FStructureEditorUtils::RemoveVariable(UBlueprint* Blueprint, FName StructName, FGuid VarGuid) { if(NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("RemoveVariable", "Remove Variable") ); Blueprint->Modify(); FBPStructureDescription* StructureDesc = Blueprint->UserDefinedStructures.FindByPredicate(FFindByNameHelper(StructName)); if(StructureDesc) { const auto OldNum = StructureDesc->Fields.Num(); StructureDesc->Fields.RemoveAll(FFindByGuidHelper(VarGuid)); if(OldNum != StructureDesc->Fields.Num()) { OnStructureChanged(*StructureDesc, Blueprint); return true; } } } return false; }
bool FStructureEditorUtils::MoveVariable(UUserDefinedStruct* Struct, FGuid VarGuid, EMoveDirection MoveDirection) { if (Struct) { const bool bMoveUp = (EMoveDirection::MD_Up == MoveDirection); auto& DescArray = GetVarDesc(Struct); const int32 InitialIndex = bMoveUp ? 1 : 0; const int32 IndexLimit = DescArray.Num() - (bMoveUp ? 0 : 1); for (int32 Index = InitialIndex; Index < IndexLimit; ++Index) { if (DescArray[Index].VarGuid == VarGuid) { const FScopedTransaction Transaction(LOCTEXT("ReorderVariables", "Varaibles reordered")); ModifyStructData(Struct); DescArray.Swap(Index, Index + (bMoveUp ? -1 : 1)); OnStructureChanged(Struct); return true; } } } return false; }
bool FStructureEditorUtils::DuplicateStructure(UBlueprint* Blueprint, FName StructName) { if(NULL != Blueprint) { const FScopedTransaction Transaction( LOCTEXT("RemoveStructure", "Remove Structure") ); Blueprint->Modify(); const FBPStructureDescription* StructureDesc = Blueprint->UserDefinedStructures.FindByPredicate(FFindByNameHelper(StructName)); if (StructureDesc) { FBPStructureDescription NewStructureDesc(*StructureDesc); NewStructureDesc.CompiledStruct = NULL; NewStructureDesc.Name = MakeUniqueStructName(Blueprint, StructureDesc->Name.ToString()); Blueprint->UserDefinedStructures.Add(NewStructureDesc); OnStructureChanged(NewStructureDesc, Blueprint); return true; } } return false; }