//------------------------------------------------------------------------------ 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; }
/** * 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; }