FText UK2Node_MacroInstance::GetTooltipText() const { UEdGraph* MacroGraph = MacroGraphReference.GetGraph(); if (FKismetUserDeclaredFunctionMetadata* Metadata = GetAssociatedGraphMetadata(MacroGraph)) { if (!Metadata->ToolTip.IsEmpty()) { return FText::FromString(Metadata->ToolTip); } } if (MacroGraph == nullptr) { return NSLOCTEXT("K2Node", "Macro_Tooltip", "Macro"); } else if (CachedTooltip.IsOutOfDate(this)) { // FText::Format() is slow, so we cache this to save on performance CachedTooltip.SetCachedText(FText::Format(NSLOCTEXT("K2Node", "MacroGraphInstance_Tooltip", "{0} instance"), FText::FromName(MacroGraph->GetFName())), this); } return CachedTooltip; }
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void FAnimTransitionNodeDetails::CustomizeDetails( IDetailLayoutBuilder& DetailBuilder ) { // Get a handle to the node we're viewing const TArray< TWeakObjectPtr<UObject> >& SelectedObjects = DetailBuilder.GetDetailsView().GetSelectedObjects(); for (int32 ObjectIndex = 0; !TransitionNode.IsValid() && (ObjectIndex < SelectedObjects.Num()); ++ObjectIndex) { const TWeakObjectPtr<UObject>& CurrentObject = SelectedObjects[ObjectIndex]; if (CurrentObject.IsValid()) { TransitionNode = Cast<UAnimStateTransitionNode>(CurrentObject.Get()); } } bool bTransitionToConduit = false; if (UAnimStateTransitionNode* TransitionNodePtr = TransitionNode.Get()) { UAnimStateNodeBase* NextState = TransitionNodePtr->GetNextState(); bTransitionToConduit = (NextState != NULL) && (NextState->IsA<UAnimStateConduitNode>()); } ////////////////////////////////////////////////////////////////////////// IDetailCategoryBuilder& TransitionCategory = DetailBuilder.EditCategory("Transition", LOCTEXT("TransitionCategoryTitle", "Transition") ); if (bTransitionToConduit) { // Transitions to conduits are just shorthand for some other real transition; // All of the blend related settings are ignored, so hide them. DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, Bidirectional)); DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, CrossfadeDuration)); DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, BlendMode)); DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, LogicType)); DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, PriorityOrder)); } else { TransitionCategory.AddCustomRow( LOCTEXT("TransitionEventPropertiesCategoryLabel", "Transition") ) [ SNew( STextBlock ) .Text( LOCTEXT("TransitionEventPropertiesCategoryLabel", "Transition") ) .Font( IDetailLayoutBuilder::GetDetailFontBold() ) ]; TransitionCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, PriorityOrder)).DisplayName(LOCTEXT("PriorityOrderLabel", "Priority Order")); TransitionCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, Bidirectional)).DisplayName(LOCTEXT("BidirectionalLabel", "Bidirectional")); TransitionCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, LogicType)).DisplayName(LOCTEXT("BlendLogicLabel", "Blend Logic") ); UAnimStateTransitionNode* TransNode = TransitionNode.Get(); if (TransitionNode != NULL) { // The sharing option for the rule TransitionCategory.AddCustomRow( LOCTEXT("TransitionRuleSharingLabel", "Transition Rule Sharing") ) [ GetWidgetForInlineShareMenu(TEXT("Transition Rule Sharing"), TransNode->SharedRulesName, TransNode->bSharedRules, FOnClicked::CreateSP(this, &FAnimTransitionNodeDetails::OnPromoteToSharedClick, true), FOnClicked::CreateSP(this, &FAnimTransitionNodeDetails::OnUnshareClick, true), FOnGetContent::CreateSP(this, &FAnimTransitionNodeDetails::OnGetShareableNodesMenu, true)) ]; // TransitionCategory.AddRow() // [ // SNew( STextBlock ) // .Text( TEXT("Crossfade Settings") ) // .Font( IDetailLayoutBuilder::GetDetailFontBold() ) // ]; // Show the rule itself UEdGraphPin* CanExecPin = NULL; if (UAnimationTransitionGraph* TransGraph = Cast<UAnimationTransitionGraph>(TransNode->BoundGraph)) { if (UAnimGraphNode_TransitionResult* ResultNode = TransGraph->GetResultNode()) { CanExecPin = ResultNode->FindPin(TEXT("bCanEnterTransition")); } } // indicate if a native transition rule applies to this UBlueprint* Blueprint = FBlueprintEditorUtils::FindBlueprintForNodeChecked(TransitionNode.Get()); if(Blueprint && Blueprint->ParentClass) { UAnimInstance* AnimInstance = CastChecked<UAnimInstance>(Blueprint->ParentClass->GetDefaultObject()); if(AnimInstance) { UEdGraph* ParentGraph = TransitionNode->GetGraph(); UAnimStateNodeBase* PrevState = TransitionNode->GetPreviousState(); UAnimStateNodeBase* NextState = TransitionNode->GetNextState(); if(PrevState != nullptr && NextState != nullptr && ParentGraph != nullptr) { FName FunctionName; if(AnimInstance->HasNativeTransitionBinding(ParentGraph->GetFName(), FName(*PrevState->GetStateName()), FName(*NextState->GetStateName()), FunctionName)) { TransitionCategory.AddCustomRow( LOCTEXT("NativeBindingPresent_Filter", "Transition has native binding") ) [ SNew(STextBlock) .Text(FText::Format(LOCTEXT("NativeBindingPresent", "Transition has native binding to {0}()"), FText::FromName(FunctionName))) .Font( IDetailLayoutBuilder::GetDetailFontBold() ) ]; } } } } TransitionCategory.AddCustomRow( CanExecPin ? CanExecPin->PinFriendlyName : FText::GetEmpty() ) [ SNew(SKismetLinearExpression, CanExecPin) ]; } ////////////////////////////////////////////////////////////////////////// IDetailCategoryBuilder& CrossfadeCategory = DetailBuilder.EditCategory("BlendSettings", LOCTEXT("BlendSettingsCategoryTitle", "BlendSettings") ); if (TransitionNode != NULL) { // The sharing option for the crossfade settings CrossfadeCategory.AddCustomRow( LOCTEXT("TransitionCrossfadeSharingLabel", "Transition Crossfade Sharing") ) [ GetWidgetForInlineShareMenu(TEXT("Transition Crossfade Sharing"), TransNode->SharedCrossfadeName, TransNode->bSharedCrossfade, FOnClicked::CreateSP(this, &FAnimTransitionNodeDetails::OnPromoteToSharedClick, false), FOnClicked::CreateSP(this, &FAnimTransitionNodeDetails::OnUnshareClick, false), FOnGetContent::CreateSP(this, &FAnimTransitionNodeDetails::OnGetShareableNodesMenu, false)) ]; } //@TODO: Gate editing these on shared non-authorative ones CrossfadeCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, CrossfadeDuration)).DisplayName( LOCTEXT("DurationLabel", "Duration") ); CrossfadeCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, BlendMode)).DisplayName( LOCTEXT("ModeLabel", "Mode") ); CrossfadeCategory.AddProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, CustomBlendCurve)).DisplayName(LOCTEXT("CurveLabel", "Custom Blend Curve")); USkeleton* TargetSkeleton = TransitionNode->GetAnimBlueprint()->TargetSkeleton; if(TargetSkeleton) { TSharedPtr<IPropertyHandle> BlendProfileHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, BlendProfile)); UObject* BlendProfilePropertyValue = nullptr; BlendProfileHandle->GetValue(BlendProfilePropertyValue); UBlendProfile* CurrentProfile = Cast<UBlendProfile>(BlendProfilePropertyValue); ISkeletonEditorModule& SkeletonEditorModule = FModuleManager::LoadModuleChecked<ISkeletonEditorModule>("SkeletonEditor"); FBlendProfilePickerArgs Args; Args.InitialProfile = CurrentProfile; Args.OnBlendProfileSelected = FOnBlendProfileSelected::CreateSP(this, &FAnimTransitionNodeDetails::OnBlendProfileChanged, BlendProfileHandle); Args.bAllowNew = false; CrossfadeCategory.AddProperty(BlendProfileHandle).CustomWidget(true) .NameContent() [ BlendProfileHandle->CreatePropertyNameWidget() ] .ValueContent() [ SkeletonEditorModule.CreateBlendProfilePicker(TargetSkeleton, Args) ]; } // Add a button that is only visible when blend logic type is custom CrossfadeCategory.AddCustomRow( LOCTEXT("EditBlendGraph", "Edit Blend Graph") ) [ SNew( SHorizontalBox ) +SHorizontalBox::Slot() .HAlign(HAlign_Right) .FillWidth(1) .Padding(0,0,10.0f,0) [ SNew(SButton) .HAlign(HAlign_Right) .OnClicked(this, &FAnimTransitionNodeDetails::OnClickEditBlendGraph) .Visibility( this, &FAnimTransitionNodeDetails::GetBlendGraphButtonVisibility ) .Text(LOCTEXT("EditBlendGraph", "Edit Blend Graph")) ] ]; ////////////////////////////////////////////////////////////////////////// IDetailCategoryBuilder& NotificationCategory = DetailBuilder.EditCategory("Notifications", LOCTEXT("NotificationsCategoryTitle", "Notifications") ); NotificationCategory.AddCustomRow( LOCTEXT("StartTransitionEventPropertiesCategoryLabel", "Start Transition Event") ) [ SNew( STextBlock ) .Text( LOCTEXT("StartTransitionEventPropertiesCategoryLabel", "Start Transition Event") ) .Font( IDetailLayoutBuilder::GetDetailFontBold() ) ]; CreateTransitionEventPropertyWidgets(NotificationCategory, TEXT("TransitionStart")); NotificationCategory.AddCustomRow( LOCTEXT("EndTransitionEventPropertiesCategoryLabel", "End Transition Event" ) ) [ SNew( STextBlock ) .Text( LOCTEXT("EndTransitionEventPropertiesCategoryLabel", "End Transition Event" ) ) .Font( IDetailLayoutBuilder::GetDetailFontBold() ) ]; CreateTransitionEventPropertyWidgets(NotificationCategory, TEXT("TransitionEnd")); NotificationCategory.AddCustomRow( LOCTEXT("InterruptTransitionEventPropertiesCategoryLabel", "Interrupt Transition Event") ) [ SNew( STextBlock ) .Text( LOCTEXT("InterruptTransitionEventPropertiesCategoryLabel", "Interrupt Transition Event") ) .Font( IDetailLayoutBuilder::GetDetailFontBold() ) ]; CreateTransitionEventPropertyWidgets(NotificationCategory, TEXT("TransitionInterrupt")); } DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, TransitionStart)); DetailBuilder.HideProperty(GET_MEMBER_NAME_CHECKED(UAnimStateTransitionNode, TransitionEnd)); }