// Copyright Epic Games, Inc. All Rights Reserved. #include "PoseWatchManagerDefaultMode.h" #include "AnimationEditorUtils.h" #include "Engine/PoseWatch.h" #include "SGraphNode.h" #include "SGraphPanel.h" #include "IAnimationBlueprintEditor.h" #include "PoseWatchManagerElementTreeItem.h" #include "PoseWatchManagerFolderTreeItem.h" #include "PoseWatchManagerPoseWatchTreeItem.h" #include "SPoseWatchManager.h" #define LOCTEXT_NAMESPACE "PoseWatchDefaultMode" /** Functor which can be used to get weak actor pointers from a selection */ struct FWeakPoseWatchSelector { bool operator()(const TWeakPtr& Item, TWeakObjectPtr& DataOut) const; }; FPoseWatchManagerDefaultMode::FPoseWatchManagerDefaultMode(SPoseWatchManager* InPoseWatchManager) : PoseWatchManager(InPoseWatchManager) { Rebuild(); } void FPoseWatchManagerDefaultMode::Rebuild() { Hierarchy = MakeUnique(this); } bool FPoseWatchManagerDefaultMode::ParseDragDrop(FPoseWatchManagerDragDropPayload& OutPayload, const FDragDropOperation& Operation) const { if (Operation.IsOfType()) { const auto& OutlinerOp = static_cast(Operation); if (const auto& PoseWatchOp = OutlinerOp.GetSubOp()) { OutPayload.DraggedItem = PoseWatchManager->GetTreeItem(PoseWatchOp->PoseWatch.Get()); } if (const auto& FolderOp = OutlinerOp.GetSubOp()) { OutPayload.DraggedItem = PoseWatchManager->GetTreeItem(FolderOp->PoseWatchFolder.Get()); } return true; } return false; } FPoseWatchManagerDragValidationInfo FPoseWatchManagerDefaultMode::ValidateDrop(const IPoseWatchManagerTreeItem& DropTarget, const FPoseWatchManagerDragDropPayload& Payload) const { if (Payload.DraggedItem.IsValid()) { TSharedPtr PayloadItem = Payload.DraggedItem.Pin(); // Pose watches cannot be a parent if (const FPoseWatchManagerPoseWatchTreeItem* PoseWatchDropTarget = DropTarget.CastTo()) { return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, LOCTEXT("PoseWatchBadParent", "A pose watch cannot be a parent")); } if (const FPoseWatchManagerElementTreeItem* ElementDropTarget = DropTarget.CastTo()) { return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, LOCTEXT("ElementBadParent", "A pose watch element cannot be a parent")); } // Drop target must either be a valid UPoseWatchFolder or nullptr denoting the root of the tree UPoseWatchFolder* TargetFolder = nullptr; FText TargetFolderLabel = LOCTEXT("Root", "root"); if (DropTarget.IsValid()) { if (const FPoseWatchManagerFolderTreeItem* DropTargetFolder = DropTarget.CastTo()) { TargetFolder = DropTargetFolder->PoseWatchFolder.Get(); if (TargetFolder) { TargetFolderLabel = TargetFolder->GetLabel(); } } } if (FPoseWatchManagerPoseWatchTreeItem* PayloadPoseWatchItem = PayloadItem->CastTo()) { // Dropping a pose watch into a folder UPoseWatch* PayloadPoseWatch = PayloadPoseWatchItem->PoseWatch.Get(); check(PayloadPoseWatch); if (PayloadPoseWatch->IsIn(TargetFolder)) { FText ValidationText = FText::Format(LOCTEXT("PoseWatchAlreadyInDirectory", "This pose watch is already inside {0}"), TargetFolderLabel); return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, ValidationText); } if (!PayloadPoseWatch->IsLabelUniqueInParent(PayloadPoseWatch->GetLabel(), TargetFolder)) { FText ValidationText = FText::Format(LOCTEXT("PoseWatchAlreadyExistsInFolder", "A pose watch with that name already exists inside {0}"), TargetFolderLabel); return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, ValidationText); } FText ValidationText = FText::Format(LOCTEXT("MovePoseWatchIntoFolder", "Move {0} into {1}"), PayloadPoseWatch->GetLabel(), TargetFolderLabel); return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Compatible, ValidationText); } else if (FPoseWatchManagerFolderTreeItem* PayloadFolderItem = PayloadItem->CastTo()) { // Dropping a folder into a folder UPoseWatchFolder* PayloadFolder = PayloadFolderItem->PoseWatchFolder.Get(); check(PayloadFolder); if (PayloadFolder == TargetFolder) { return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, LOCTEXT("FolderInItself", "A folder cannot contain itself")); } if (PayloadFolder->IsIn(TargetFolder)) { FText ValidationText = FText::Format(LOCTEXT("FolderAlreadyInDirectory", "This folder is already inside {0}"), TargetFolderLabel); return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, ValidationText); } if (TargetFolder && TargetFolder->IsDescendantOf(PayloadFolder)) { return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, LOCTEXT("ParentFolderNotChildren", "Parent folders cannot be children")); } if (!PayloadFolder->IsLabelUniqueInParent(PayloadFolder->GetLabel(), TargetFolder)) { FText ValidationText = FText::Format(LOCTEXT("FolderNameConflictInFolder", "A folder with that name already exists inside {0}"), TargetFolderLabel); return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, ValidationText); } FText ValidationText = FText::Format(LOCTEXT("MoveFolderIntoFolder", "Move {0} into {1}"), PayloadFolder->GetLabel(), TargetFolderLabel); return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Compatible, ValidationText); } } return FPoseWatchManagerDragValidationInfo(EPoseWatchManagerDropCompatibility::Incompatible, FText()); } void FPoseWatchManagerDefaultMode::OnDrop(IPoseWatchManagerTreeItem& DropTarget, const FPoseWatchManagerDragDropPayload& Payload, const FPoseWatchManagerDragValidationInfo& ValidationInfo) const { check(Payload.DraggedItem.IsValid()); check(DropTarget.IsA()); const FPoseWatchManagerFolderTreeItem* FolderDropTarget = DropTarget.CastTo(); const TWeakPtr PayloadItem = Payload.DraggedItem; if (const FPoseWatchManagerFolderTreeItem* ChildFolderItem = PayloadItem.Pin()->CastTo()) { ChildFolderItem->PoseWatchFolder->MoveTo(FolderDropTarget->PoseWatchFolder.Get()); return; } if (const FPoseWatchManagerPoseWatchTreeItem* ChildPoseWatchItem = PayloadItem.Pin()->CastTo()) { ChildPoseWatchItem->PoseWatch->MoveTo(FolderDropTarget->PoseWatchFolder.Get()); return; } check(false); } TSharedPtr FPoseWatchManagerDefaultMode::CreateDragDropOperation(const TArray& InTreeItems) const { check(InTreeItems.Num() == 1) FPoseWatchManagerTreeItemPtr TreeItem = InTreeItems[0]; FPoseWatchManagerDragDropPayload DraggedObjects(TreeItem); TSharedPtr OutlinerOp = MakeShareable(new FPoseWatchManagerDragDropOp()); if (FPoseWatchManagerPoseWatchTreeItem* PoseWatchTreeItem = TreeItem->CastTo()) { TSharedPtr Operation = MakeShareable(new FPoseWatchDragDropOp); Operation->Init(TWeakObjectPtr(PoseWatchTreeItem->PoseWatch)); OutlinerOp->AddSubOp(Operation); } else if (FPoseWatchManagerFolderTreeItem* FolderTreeItem = TreeItem->CastTo()) { TSharedPtr Operation = MakeShareable(new FPoseWatchFolderDragDropOp); Operation->Init(TWeakObjectPtr(FolderTreeItem->PoseWatchFolder)); OutlinerOp->AddSubOp(Operation); } OutlinerOp->Construct(); return OutlinerOp; } FReply FPoseWatchManagerDefaultMode::OnDragOverItem(const FDragDropEvent& Event, const IPoseWatchManagerTreeItem& Item) const { return FReply::Handled(); } #undef LOCTEXT_NAMESPACE