//------------------------------------------------------------------------------
bool FKismetDragDropAction::ActionWillShowExistingNode() const
{
	bool bWillFocusOnExistingNode = false;

	UEdGraph* TheHoveredGraph = GetHoveredGraph();
	if (ActionNode.IsValid() && (TheHoveredGraph != nullptr))
	{
		bWillFocusOnExistingNode = (ActionNode->GetTypeId() == FEdGraphSchemaAction_K2TargetNode::StaticGetTypeId()) ||
			(ActionNode->GetTypeId() == FEdGraphSchemaAction_K2InputAction::StaticGetTypeId());

		if (!bWillFocusOnExistingNode)
		{
			if (ActionNode->GetTypeId() == FEdGraphSchemaAction_K2AddEvent::StaticGetTypeId())
			{
				FEdGraphSchemaAction_K2AddEvent* AddEventAction = (FEdGraphSchemaAction_K2AddEvent*)ActionNode.Get();
				bWillFocusOnExistingNode = AddEventAction->EventHasAlreadyBeenPlaced(FBlueprintEditorUtils::FindBlueprintForGraph(TheHoveredGraph));
			}
			else if (ActionNode->GetTypeId() == FEdGraphSchemaAction_K2Event::StaticGetTypeId())
			{
				FEdGraphSchemaAction_K2Event* FuncAction = (FEdGraphSchemaAction_K2Event*)ActionNode.Get();
				UK2Node_CustomEvent* CustomEvent = Cast<UK2Node_CustomEvent>(FuncAction->NodeTemplate);
				// Drag and dropping custom event's will place a Call Function and will not focus the existing event
				if (CustomEvent == nullptr)
				{
					bWillFocusOnExistingNode = true;
				}
			}
		}
	}

	return bWillFocusOnExistingNode;
}
示例#2
0
/**
 * Checks to see if the user can drop the currently dragged action to place its
 * associated node in the graph.
 * 
 * @param  DropActionIn			The action that will be executed when the user drops the dragged item.
 * @param  HoveredGraphIn		A pointer to the graph that the user currently has the item dragged over.
 * @param  ImpededReasonOut		If this returns false, this will be filled out with a reason to present the user with.
 * @return True is the dragged palette item can be dropped where it currently is, false if not.
 */
static bool CanPaletteItemBePlaced(TSharedPtr<FEdGraphSchemaAction> DropActionIn, UEdGraph* HoveredGraphIn, FText& ImpededReasonOut)
{
	bool bCanBePlaced = true;
	if (!DropActionIn.IsValid())
	{
		bCanBePlaced = false;
		ImpededReasonOut = LOCTEXT("InvalidDropAction", "Invalid action for placement");
	}
	else if (HoveredGraphIn == NULL)
	{
		bCanBePlaced = false;
		ImpededReasonOut = LOCTEXT("DropOnlyInGraph", "Nodes can only be placed inside the blueprint graph");
	}
	else if (UK2Node const* NodeToBePlaced = FBlueprintActionMenuUtils::ExtractNodeTemplateFromAction(DropActionIn))
	{
		UEdGraphSchema const* const GraphSchema = HoveredGraphIn->GetSchema();
		check(GraphSchema != nullptr);

		bool bIsFunctionGraph = (GraphSchema->GetGraphType(HoveredGraphIn) == EGraphType::GT_Function);

		if (UK2Node_CallFunction const* CallFuncNode = Cast<UK2Node_CallFunction const>(NodeToBePlaced))
		{
			FName const FuncName = CallFuncNode->FunctionReference.GetMemberName();
			check(FuncName != NAME_None);
			UClass const* const FuncOwner = CallFuncNode->FunctionReference.GetMemberParentClass(CallFuncNode);
			check(FuncOwner != nullptr);

			UFunction* const Function = FindField<UFunction>(FuncOwner, FuncName);
			UEdGraphSchema_K2 const* const K2Schema = Cast<UEdGraphSchema_K2 const>(GraphSchema);

			if (Function == nullptr)
			{
				bCanBePlaced = false;
				ImpededReasonOut = LOCTEXT("InvalidFuncAction", "Invalid function for placement");
			}
			else if (K2Schema == nullptr)
			{
				bCanBePlaced = false;
				ImpededReasonOut = LOCTEXT("CannotCreateInThisSchema", "Cannot call functions in this type of graph");
			}
			else
			{
				// Note: We only check function context for UK2Node_CallFunction types specifically; derivatives are typically bound to specific functions that should be placeable but may not be explicitly callable (e.g. InternalUseOnly).
				// @TODO - Consolidate this as a call to UK2Node::IsActionFilteredOut() here instead? Would need to add the ImpededReason as an 'out' param to that API first.
				//  	   We could then also skip the additonal 'CanPasteHere' check below in that case as it would be redundant for CallFunction node types specifically.
				if(NodeToBePlaced->GetClass() == UK2Node_CallFunction::StaticClass())
				{ 
					uint32 AllowedFunctionTypes = UEdGraphSchema_K2::EFunctionType::FT_Pure | UEdGraphSchema_K2::EFunctionType::FT_Const | UEdGraphSchema_K2::EFunctionType::FT_Protected;
					if(K2Schema->DoesGraphSupportImpureFunctions(HoveredGraphIn))
					{
						AllowedFunctionTypes |= UEdGraphSchema_K2::EFunctionType::FT_Imperative;
					}

					const UClass* GeneratedClass = FBlueprintEditorUtils::FindBlueprintForGraphChecked(HoveredGraphIn)->GeneratedClass;
					bCanBePlaced = K2Schema->CanFunctionBeUsedInGraph(GeneratedClass, Function, HoveredGraphIn, AllowedFunctionTypes, false, FFunctionTargetInfo(), &ImpededReasonOut);
				}
			}
		}
		else if (UK2Node_Event const* EventNode = Cast<UK2Node_Event const>(NodeToBePlaced))
		{
			// function graphs cannot have more than one entry point
			if (bIsFunctionGraph)
			{
				bCanBePlaced = false;
				ImpededReasonOut = LOCTEXT("NoSecondEntryPoint", "Function graphs can only have one entry point");
			}
			else if (GraphSchema->GetGraphType(HoveredGraphIn) != EGraphType::GT_Ubergraph)
			{
				bCanBePlaced = false;
				ImpededReasonOut = LOCTEXT("NoEventsOnlyInUberGraphs", "Events can only be placed in event graphs");
			}
		}
		else if (Cast<UK2Node_SpawnActor const>(NodeToBePlaced) || Cast<UK2Node_SpawnActorFromClass const>(NodeToBePlaced))
		{
			UEdGraphSchema_K2 const* const K2Schema = Cast<UEdGraphSchema_K2 const>(GraphSchema);
			if (K2Schema && K2Schema->IsConstructionScript(HoveredGraphIn))
			{
				bCanBePlaced = false;
				ImpededReasonOut = LOCTEXT("NoSpawnActorInConstruction", "Cannot spawn actors from a construction script");
			}
		}

		bool bWillFocusOnExistingNode = (DropActionIn->GetTypeId() == FEdGraphSchemaAction_K2TargetNode::StaticGetTypeId());
		if (!bWillFocusOnExistingNode && DropActionIn->GetTypeId() == FEdGraphSchemaAction_K2AddEvent::StaticGetTypeId())
		{
			FEdGraphSchemaAction_K2AddEvent* AddEventAction = (FEdGraphSchemaAction_K2AddEvent*)DropActionIn.Get();
			bWillFocusOnExistingNode = AddEventAction->EventHasAlreadyBeenPlaced(FBlueprintEditorUtils::FindBlueprintForGraph(HoveredGraphIn));
		}
		
		// if this will instead focus on an existing node, reverse any previous decision... it is ok to drop!
		if (bWillFocusOnExistingNode)
		{
			bCanBePlaced = true;
			ImpededReasonOut = FText::GetEmpty();
		}
		// as a general catch-all, if a node cannot be pasted or placed in the graph, it probably can't be created there.
		// Some nodes allow themselves to be pasted where they are generally not allowed, if either does not want the 
		// node placed, it should not be placeable
		else if (bCanBePlaced && (!NodeToBePlaced->CanPasteHere(HoveredGraphIn) || !NodeToBePlaced->IsCompatibleWithGraph(HoveredGraphIn)) && !bWillFocusOnExistingNode)
		{
			bCanBePlaced = false;
			ImpededReasonOut = LOCTEXT("CannotPaste", "Cannot place this node in this type of graph");
		}
	}

	return bCanBePlaced;
}