//------------------------------------------------------------------------------ FReply FKismetFunctionDragDropAction::DroppedOnPanel(TSharedRef<SWidget> const& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) { FReply Reply = FReply::Unhandled(); // The ActionNode set during construction points to the Graph, this is suitable for displaying the mouse decorator but needs to be more complete based on the current graph UBlueprintFunctionNodeSpawner* FunctionNodeSpawner = nullptr; FunctionNodeSpawner = GetDropAction(Graph); if (FunctionNodeSpawner) { FText CannotDropReason = FText::GetEmpty(); if (!CanBeDroppedDelegate.IsBound() || CanBeDroppedDelegate.Execute(nullptr, GetHoveredGraph(), CannotDropReason)) { UFunction const* Function = GetFunctionProperty(); if ((Function != NULL) && UEdGraphSchema_K2::CanUserKismetCallFunction(Function)) { AnalyticCallback.ExecuteIfBound(); IBlueprintNodeBinder::FBindingSet Bindings; FunctionNodeSpawner->Invoke(&Graph, Bindings, GraphPosition); Reply = FReply::Handled(); } } } return Reply; }
//------------------------------------------------------------------------------ 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; }
//------------------------------------------------------------------------------ void FKismetMacroDragDropAction::HoverTargetChanged() { UEdGraph* TheHoveredGraph = GetHoveredGraph(); FText CannotDropReason = FText::GetEmpty(); // it should be obvious that we can't drop on anything but a graph, so no need to point that out if ((TheHoveredGraph == NULL) || !CanBeDroppedDelegate.IsBound() || CanBeDroppedDelegate.Execute(ActionNode, TheHoveredGraph, CannotDropReason)) { FSlateBrush const* DropPreventedIcon = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.NewNode")); SetSimpleFeedbackMessage(DropPreventedIcon, FLinearColor::White, FText::FromName(MacroName)); } else { FSlateBrush const* DropPreventedIcon = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); SetSimpleFeedbackMessage(DropPreventedIcon, FLinearColor::White, CannotDropReason); } }
//------------------------------------------------------------------------------ FReply FKismetDragDropAction::DroppedOnPanel( const TSharedRef< SWidget >& Panel, FVector2D ScreenPosition, FVector2D GraphPosition, UEdGraph& Graph) { FReply Reply = FReply::Unhandled(); FText CannotDropReason = FText::GetEmpty(); if (!CanBeDroppedDelegate.IsBound() || CanBeDroppedDelegate.Execute(ActionNode, GetHoveredGraph(), CannotDropReason)) { Reply = FGraphSchemaActionDragDropAction::DroppedOnPanel(Panel, ScreenPosition, GraphPosition, Graph); } if (Reply.IsEventHandled()) { AnalyticCallback.ExecuteIfBound(); } return Reply; }
//------------------------------------------------------------------------------ void FKismetDragDropAction::HoverTargetChanged() { UEdGraph* TheHoveredGraph = GetHoveredGraph(); FText CannotDropReason = FText::GetEmpty(); if (ActionWillShowExistingNode()) { FSlateBrush const* ShowsExistingIcon = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.ShowNode")); FText DragingText = FText::Format(LOCTEXT("ShowExistingNode", "Show '{0}'"), ActionNode->GetMenuDescription()); SetSimpleFeedbackMessage(ShowsExistingIcon, FLinearColor::White, DragingText); } // it should be obvious that we can't drop on anything but a graph, so no need to point that out else if ((TheHoveredGraph == nullptr) || !CanBeDroppedDelegate.IsBound() || CanBeDroppedDelegate.Execute(ActionNode, TheHoveredGraph, CannotDropReason)) { FGraphSchemaActionDragDropAction::HoverTargetChanged(); } else { FSlateBrush const* DropPreventedIcon = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); SetSimpleFeedbackMessage(DropPreventedIcon, FLinearColor::White, CannotDropReason); } }
void FKismetVariableDragDropAction::HoverTargetChanged() { UProperty* VariableProperty = GetVariableProperty(); if (VariableProperty == nullptr) { return; } FString VariableString = VariableName.ToString(); // Icon/text to draw on tooltip FSlateColor IconColor = FLinearColor::White; const FSlateBrush* StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); FText Message = LOCTEXT("InvalidDropTarget", "Invalid drop target!"); UEdGraphPin* PinUnderCursor = GetHoveredPin(); bool bCanMakeSetter = true; bool bBadSchema = false; bool bBadGraph = false; UEdGraph* HoveredGraph = GetHoveredGraph(); if (HoveredGraph) { if (Cast<const UEdGraphSchema_K2>(HoveredGraph->GetSchema()) == NULL) { bBadSchema = true; } else if(!CanVariableBeDropped(VariableProperty, *HoveredGraph)) { bBadGraph = true; } UStruct* Outer = CastChecked<UStruct>(VariableProperty->GetOuter()); FNodeConstructionParams NewNodeParams; NewNodeParams.VariableName = VariableName; const UBlueprint* DropOnBlueprint = FBlueprintEditorUtils::FindBlueprintForGraph(HoveredGraph); NewNodeParams.Graph = HoveredGraph; NewNodeParams.VariableSource = Outer; bCanMakeSetter = CanExecuteMakeSetter(NewNodeParams, VariableProperty); } UEdGraphNode* VarNodeUnderCursor = Cast<UK2Node_Variable>(GetHoveredNode()); if (bBadSchema) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = LOCTEXT("CannotCreateInThisSchema", "Cannot access variables in this type of graph"); } else if(bBadGraph) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); Args.Add(TEXT("Scope"), FText::FromString(HoveredGraph->GetName())); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); if(IsFromBlueprint(FBlueprintEditorUtils::FindBlueprintForGraph(HoveredGraph)) && VariableProperty->GetOuter()->IsA(UFunction::StaticClass())) { Message = FText::Format( LOCTEXT("IncorrectGraphForLocalVariable_Error", "Cannot place local variable '{VariableName}' in external scope '{Scope}'"), Args); } else { Message = FText::Format( LOCTEXT("IncorrectGraphForVariable_Error", "Cannot place variable '{VariableName}' in external scope '{Scope}'"), Args); } } else if (PinUnderCursor != NULL) { FFormatNamedArguments Args; Args.Add(TEXT("PinUnderCursor"), FText::FromString(PinUnderCursor->PinName)); Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); if(CanVariableBeDropped(VariableProperty, *PinUnderCursor->GetOwningNode()->GetGraph())) { const UEdGraphSchema_K2* Schema = CastChecked<const UEdGraphSchema_K2>(PinUnderCursor->GetSchema()); const bool bIsRead = PinUnderCursor->Direction == EGPD_Input; const UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(PinUnderCursor->GetOwningNode()); const bool bReadOnlyProperty = FBlueprintEditorUtils::IsPropertyReadOnlyInCurrentBlueprint(Blueprint, VariableProperty); const bool bCanWriteIfNeeded = bIsRead || !bReadOnlyProperty; FEdGraphPinType VariablePinType; Schema->ConvertPropertyToPinType(VariableProperty, VariablePinType); const bool bTypeMatch = Schema->ArePinTypesCompatible(VariablePinType, PinUnderCursor->PinType); Args.Add(TEXT("PinUnderCursor"), FText::FromString(PinUnderCursor->PinName)); if (bTypeMatch && bCanWriteIfNeeded) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); if (bIsRead) { Message = FText::Format(LOCTEXT("MakeThisEqualThat_PinEqualVariableName", "Make {PinUnderCursor} = {VariableName}"), Args); } else { Message = FText::Format(LOCTEXT("MakeThisEqualThat_VariableNameEqualPin", "Make {VariableName} = {PinUnderCursor}"), Args); } } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); if (!bCanWriteIfNeeded) { Message = FText::Format(LOCTEXT("ReadOnlyVar_Error", "Cannot write to read-only variable '{VariableName}'"), Args); } else { Message = FText::Format(LOCTEXT("NotCompatible_Error", "The type of '{VariableName}' is not compatible with {PinUnderCursor}"), Args); } } } else { Args.Add(TEXT("Scope"), FText::FromString(PinUnderCursor->GetOwningNode()->GetGraph()->GetName())); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("IncorrectGraphForPin_Error", "Cannot place local variable '{VariableName}' in external scope '{Scope}'"), Args); } } else if (VarNodeUnderCursor != NULL) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); if(CanVariableBeDropped(VariableProperty, *VarNodeUnderCursor->GetGraph())) { const bool bIsRead = VarNodeUnderCursor->IsA(UK2Node_VariableGet::StaticClass()); const UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNode(VarNodeUnderCursor); const bool bReadOnlyProperty = FBlueprintEditorUtils::IsPropertyReadOnlyInCurrentBlueprint(Blueprint, VariableProperty); const bool bCanWriteIfNeeded = bIsRead || !bReadOnlyProperty; if (bCanWriteIfNeeded) { Args.Add(TEXT("ReadOrWrite"), bIsRead ? LOCTEXT("Read", "read") : LOCTEXT("Write", "write")); if(WillBreakLinks(VarNodeUnderCursor, VariableProperty)) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OKWarn")); Message = FText::Format( LOCTEXT("ChangeNodeToWarnBreakLinks", "Change node to {ReadOrWrite} '{VariableName}', WARNING this will break links!"), Args); } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); Message = FText::Format( LOCTEXT("ChangeNodeTo", "Change node to {ReadOrWrite} '{VariableName}'"), Args); } } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("ReadOnlyVar_Error", "Cannot write to read-only variable '{VariableName}'"), Args); } } else { Args.Add(TEXT("Scope"), FText::FromString(VarNodeUnderCursor->GetGraph()->GetName())); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("IncorrectGraphForNodeReplace_Error", "Cannot replace node with local variable '{VariableName}' in external scope '{Scope}'"), Args); } } else if (!HoveredCategoryName.IsEmpty()) { // Find Blueprint that made this class and get category of variable FText Category; UBlueprint* Blueprint; // Find the Blueprint for this property if(Cast<UFunction>(VariableSource.Get())) { Blueprint = UBlueprint::GetBlueprintFromClass(Cast<UClass>(VariableSource->GetOuter())); } else { Blueprint = UBlueprint::GetBlueprintFromClass(Cast<UClass>(VariableSource.Get())); } if(Blueprint != NULL) { Category = FBlueprintEditorUtils::GetBlueprintVariableCategory(Blueprint, VariableProperty->GetFName(), GetLocalVariableScope() ); } // See if class is native UClass* OuterClass = Cast<UClass>(VariableProperty->GetOuter()); if(OuterClass || Cast<UFunction>(VariableProperty->GetOuter())) { const bool bIsNativeVar = (OuterClass && OuterClass->ClassGeneratedBy == NULL); FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); Args.Add(TEXT("HoveredCategoryName"), HoveredCategoryName); if (bIsNativeVar) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("ChangingCatagoryNotThisVar", "Cannot change category for variable '{VariableName}'"), Args ); } else if (Category.EqualTo(HoveredCategoryName)) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("ChangingCatagoryAlreadyIn", "Variable '{VariableName}' is already in category '{HoveredCategoryName}'"), Args ); } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); Message = FText::Format( LOCTEXT("ChangingCatagoryOk", "Move variable '{VariableName}' to category '{HoveredCategoryName}'"), Args ); } } } else if (HoveredAction.IsValid()) { if(HoveredAction.Pin()->GetTypeId() == FEdGraphSchemaAction_K2Var::StaticGetTypeId()) { FEdGraphSchemaAction_K2Var* VarAction = (FEdGraphSchemaAction_K2Var*)HoveredAction.Pin().Get(); FName TargetVarName = VarAction->GetVariableName(); // Needs to have a valid index to move it (this excludes variables added through other means, like timelines/components int32 MoveVarIndex = INDEX_NONE; int32 TargetVarIndex = INDEX_NONE; UBlueprint* Blueprint = UBlueprint::GetBlueprintFromClass(Cast<UClass>(VariableSource.Get())); if(Blueprint != NULL) { MoveVarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, VariableName); TargetVarIndex = FBlueprintEditorUtils::FindNewVariableIndex(Blueprint, TargetVarName); } FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); Args.Add(TEXT("TargetVarName"), FText::FromName(TargetVarName)); if(MoveVarIndex == INDEX_NONE) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("MoveVarDiffClass", "Cannot reorder variable '{VariableName}'."), Args ); } else if(TargetVarIndex == INDEX_NONE) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("MoveVarOther", "Cannot reorder variable '{VariableName}' before '{TargetVarName}'."), Args ); } else if(VariableName == TargetVarName) { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format( LOCTEXT("MoveVarYourself", "Cannot reorder variable '{VariableName}' before itself."), Args ); } else { StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK")); Message = FText::Format( LOCTEXT("MoveVarOK", "Reorder variable '{VariableName}' before '{TargetVarName}'"), Args ); } } } else if (bAltDrag && !bCanMakeSetter) { FFormatNamedArguments Args; Args.Add(TEXT("VariableName"), FText::FromString(VariableString)); StatusSymbol = FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error")); Message = FText::Format(LOCTEXT("CannotPlaceSetter", "Variable '{VariableName}' is readonly, you cannot set this variable."), Args); } // Draw variable icon else { StatusSymbol = FBlueprintEditor::GetVarIconAndColor(VariableSource.Get(), VariableName, IconColor); Message = FText::FromString(VariableString); } SetSimpleFeedbackMessage(StatusSymbol, IconColor, Message); }