// Copyright Epic Games, Inc. All Rights Reserved. #if WITH_EDITOR #include "SchematicGraphPanel/SchematicGraphNode.h" #include "SchematicGraphPanel/SchematicGraphModel.h" #include #include "Framework/Application/SlateApplication.h" #define LOCTEXT_NAMESPACE "SchematicGraphNode" FSchematicGraphNode::FSchematicGraphNode() { static const FSlateBrush* BackgroundBrush = FSchematicGraphStyle::Get().GetBrush( "Schematic.Background"); static const FSlateBrush* OutlineBrush = FSchematicGraphStyle::Get().GetBrush( "Schematic.Outline.Single"); static const FSlateBrush* DotBrush = FSchematicGraphStyle::Get().GetBrush( "Schematic.Dot.Small"); Brushes = { BackgroundBrush, OutlineBrush, DotBrush }; Colors = { FLinearColor::White * 0.4f, FLinearColor::White, FLinearColor::Blue }; } FSchematicGraphNode* FSchematicGraphNode::GetParentNode() { if(Model && ParentNodeGuid.IsValid()) { return Model->FindNode(ParentNodeGuid); } return nullptr; } const FSchematicGraphNode* FSchematicGraphNode::GetParentNode() const { return const_cast(this)->GetParentNode(); } const FGuid& FSchematicGraphNode::GetRootNodeGuid() const { if(const FSchematicGraphNode* ParentNode = GetParentNode()) { return ParentNode->GetRootNodeGuid(); } return GetGuid(); } FSchematicGraphNode* FSchematicGraphNode::GetRootNode() { if(Model) { return Model->FindNode(GetRootNodeGuid()); } return nullptr; } const FSchematicGraphNode* FSchematicGraphNode::GetRootNode() const { return const_cast(this)->GetRootNode(); } FSchematicGraphGroupNode* FSchematicGraphNode::GetGroupNode() { return Cast(GetParentNode()); } const FSchematicGraphGroupNode* FSchematicGraphNode::GetGroupNode() const { return const_cast(this)->GetGroupNode(); } const FSchematicGraphNode* FSchematicGraphNode::GetChildNode(int32 InChildNodeIndex) const { return const_cast(this)->GetChildNode(InChildNodeIndex); } FSchematicGraphNode* FSchematicGraphNode::GetChildNode(int32 InChildNodeIndex) { check(ChildNodeGuids.IsValidIndex(InChildNodeIndex)); const FGuid& ChildNodeGuid = ChildNodeGuids[InChildNodeIndex]; if(Model && ChildNodeGuid.IsValid()) { return Model->FindNode(ChildNodeGuid); } return nullptr; } TOptional FSchematicGraphNode::GetVisibilityForChildNode(const FGuid& InChildGuid) const { if(Model) { if(const FSchematicGraphNode* ChildNode = Model->FindNode(InChildGuid)) { return GetVisibilityForChildNode(ChildNode); } } return TOptional(); } TOptional FSchematicGraphNode::GetPositionForChildNode(const FGuid& InChildGuid) const { if(Model) { if(const FSchematicGraphNode* ChildNode = Model->FindNode(InChildGuid)) { return GetPositionForChildNode(ChildNode); } } return TOptional(); } TOptional FSchematicGraphNode::GetScaleForChildNode(const FGuid& InChildGuid) const { if(Model) { if(const FSchematicGraphNode* ChildNode = Model->FindNode(InChildGuid)) { return GetScaleForChildNode(ChildNode); } } return TOptional(); } TOptional FSchematicGraphNode::GetInteractivityForChildNode(const FGuid& InChildGuid) const { if(Model) { if(const FSchematicGraphNode* ChildNode = Model->FindNode(InChildGuid)) { return GetInteractivityForChildNode(ChildNode); } } return TOptional(); } FVector2d FSchematicGraphNode::GetPosition() const { if(const FSchematicGraphNode* ParentNode = GetParentNode()) { const TOptional ParentPosition = Model->GetPositionForChildNode(ParentNode, this); if(ParentPosition.IsSet()) { return ParentPosition.GetValue(); } } return Position; } const FText& FSchematicGraphNode::GetToolTip() const { return ToolTip; } ESchematicGraphVisibility::Type FSchematicGraphNode::GetVisibility() const { if(Visibility == ESchematicGraphVisibility::Hidden) { return Visibility; } const FSchematicGraphNode* ParentNode = GetParentNode(); if(const FSchematicGraphGroupNode* LastExpandedNode = Model->GetLastExpandedNode()) { if(LastExpandedNode != this && LastExpandedNode != ParentNode) { return ESchematicGraphVisibility::FadedOut; } } if(ParentNode) { const TOptional ParentVisibility = Model->GetVisibilityForChildNode(ParentNode, this); if(ParentVisibility.IsSet()) { return ParentVisibility.GetValue(); } } return Visibility; } bool FSchematicGraphNode::IsInteractive() const { if(GetVisibility() != ESchematicGraphVisibility::Visible) { return false; } if(const FSchematicGraphNode* ParentNode = GetParentNode()) { const TOptional ParentInteractivity = Model->GetInteractivityForChildNode(ParentNode, this); if(ParentInteractivity.IsSet()) { return ParentInteractivity.GetValue(); } } return true; } FReply FSchematicGraphNode::OnClicked(const FPointerEvent& InMouseEvent) { return FReply::Unhandled(); } void FSchematicGraphNode::OnMouseEnter() { SetScaleOffset(ScaledUp); } void FSchematicGraphNode::OnMouseLeave() { SetScaleOffset(1.f); } void FSchematicGraphNode::OnDragOver() { SetScaleOffset(ScaledDown); if(FSchematicGraphGroupNode* GroupNode = const_cast(GetGroupNode())) { GroupNode->SetExpanded(true); } } void FSchematicGraphNode::OnDragLeave() { SetScaleOffset(1.f); if(FSchematicGraphGroupNode* GroupNode = const_cast(GetGroupNode())) { GroupNode->SetExpanded(false); } } FString FSchematicGraphNode::GetDragDropDecoratorLabel() const { return GetGuid().ToString(); } bool FSchematicGraphNode::RemoveTag(const FGuid& InTagGuid) { if(const FSchematicGraphTag* Tag = FindTag(InTagGuid)) { if (Model && Model->OnTagRemovedDelegate.IsBound()) { Model->OnTagRemovedDelegate.Broadcast(this, Tag); } const FGuid TagGuid = Tag->GetGuid(); TagByGuid.Remove(Tag->GetGuid()); Tags.RemoveAll([TagGuid](const TSharedPtr& ExistingTag) -> bool { return ExistingTag->GetGuid() == TagGuid; }); return true; } return false; } void FSchematicGraphNode::NotifyTagAdded(const TSharedPtr& Tag) { if (Model != nullptr && Model->OnTagAddedDelegate.IsBound()) { Model->OnTagAddedDelegate.Broadcast(this, Tag.Get()); } } FSchematicGraphGroupNode::FSchematicGraphGroupNode() : AnimationSettings(EEasingInterpolatorType::CubicEaseOut, 0.35f) { static const FSlateBrush* BackgroundBrush = FSchematicGraphStyle::Get().GetBrush( "Schematic.Background"); static const FSlateBrush* OutlineBrush = FSchematicGraphStyle::Get().GetBrush( "Schematic.Outline.Single"); static const FSlateBrush* GroupBrush = FSchematicGraphStyle::Get().GetBrush( "Schematic.Dot.Group"); Brushes = { BackgroundBrush, OutlineBrush, GroupBrush }; Colors = { FLinearColor::White * 0.4f, FLinearColor::White, FLinearColor::Gray }; ExpansionState = TAnimatedAttribute::Create(AnimationSettings, 0.f); (void)AddTag(); } bool FSchematicGraphGroupNode::IsExpanded() const { return GetExpansionState() > SMALL_NUMBER; } bool FSchematicGraphGroupNode::IsExpanding() const { return (ExpansionState->Get() < 1.f - SMALL_NUMBER) && (ExpansionState->GetDesiredValue() >= 1.f - SMALL_NUMBER); } bool FSchematicGraphGroupNode::IsCollapsing() const { return (ExpansionState->Get() >= SMALL_NUMBER) && (ExpansionState->GetDesiredValue() < SMALL_NUMBER); } float FSchematicGraphGroupNode::GetExpansionState() const { if(!ExpansionState.IsValid()) { return 0.f; } return ExpansionState->Get(); } void FSchematicGraphGroupNode::SetExpanded(bool InExpanded, bool bAutoCloseParentGroups) { if(InExpanded) { if(GetNumChildNodes() == 0) { return; } } if(!InExpanded && GetExpansionState() < SMALL_NUMBER) { ExpansionState->SetValueAndStop(0.f); LastExpansionState.Reset(); } else { if(InExpanded && !ExpansionState->IsPlaying()) { // set the state to an initial value so that IsExpanded will return correctly if(ExpansionState->Get() < SMALL_NUMBER) { ExpansionState->SetValueAndStop(SMALL_NUMBER * 2.f); } } if(!LastExpansionState.IsSet() || (LastExpansionState.Get(InExpanded) != InExpanded)) { if(!ExpansionState->GetDelay().IsSet()) { ExpansionState->SetDelayOneShot(GetDelayDuration(InExpanded)); } LastExpansionState = InExpanded; } ExpansionState->Set(InExpanded ? 1.f : 0.f); } if(InExpanded || bAutoCloseParentGroups) { if(FSchematicGraphGroupNode* GroupNode = const_cast(GetGroupNode())) { GroupNode->SetExpanded(InExpanded, bAutoCloseParentGroups); } } if(InExpanded) { Model->SetLastExpandedNode(this); } else if(const FSchematicGraphGroupNode* GroupNode = GetGroupNode()) { if(GroupNode->IsExpanded()) { Model->SetLastExpandedNode(GroupNode); } } // also collapse all child nodes if(!InExpanded) { for(int32 ChildIndex = 0; ChildIndex < GetNumChildNodes(); ChildIndex++) { if(FSchematicGraphGroupNode* ChildNode = Cast(GetChildNode(ChildIndex))) { ChildNode->SetExpanded(false); } } } } TOptional FSchematicGraphGroupNode::GetVisibilityForChildNode(const FSchematicGraphNode* InChildNode) const { if(!IsExpanded()) { return ESchematicGraphVisibility::Hidden; } return Super::GetVisibilityForChildNode(InChildNode); } TOptional FSchematicGraphGroupNode::GetPositionForChildNode(const FSchematicGraphNode* InChildNode) const { if(IsExpanded() && Model) { const int32 ChildNodeIndex = ChildNodeGuids.Find(InChildNode->GetGuid()); if(ChildNodeIndex != INDEX_NONE) { const float Distance = ExpansionRadius * GetExpansionState(); const float Angle = 360.f * float(ChildNodeIndex) / float(ChildNodeGuids.Num()); const FVector2d Offset = FVector2d(Distance, 0).GetRotated(Angle); return Model->GetPositionForNode(this) + Offset; } } return Super::GetPositionForChildNode(InChildNode); } TOptional FSchematicGraphGroupNode::GetScaleForChildNode(const FSchematicGraphNode* InChildNode) const { if(IsExpanded() && Model) { return GetExpansionState(); } return Super::GetScaleForChildNode(InChildNode); } TOptional FSchematicGraphGroupNode::GetInteractivityForChildNode(const FSchematicGraphNode* InChildNode) const { if(GetExpansionState() < 1.f - SMALL_NUMBER) { return false; } return Super::GetInteractivityForChildNode(InChildNode); } FReply FSchematicGraphGroupNode::OnClicked(const FPointerEvent& InMouseEvent) { if(GetNumChildNodes() > 0) { if(!InMouseEvent.GetModifierKeys().AnyModifiersDown()) { SetExpanded(!IsExpanded()); } return FReply::Handled(); } return FSchematicGraphNode::OnClicked(InMouseEvent); } void FSchematicGraphGroupNode::OnDragOver() { Super::OnDragOver(); SetExpanded(true, true); } void FSchematicGraphGroupNode::OnDragLeave() { Super::OnDragLeave(); SetExpanded(false, true); } float FSchematicGraphGroupNode::GetDelayDuration(bool bEnter) const { if (FSlateApplication::Get().IsDragDropping()) { return bEnter ? EnterDelayDuration : LeaveDelayDuration; } return 0.f; } void FSchematicGraphGroupNode::SetAnimationSettings(const TEasingAttributeInterpolator::FSettings& InSettings) { ExpansionState = TAnimatedAttribute::Create(AnimationSettings, IsExpanded() ? 1.f : 0.f); } const FText& FSchematicGraphAutoGroupNode::GetLabel() const { const FText& SuperLabel = FSchematicGraphGroupNode::GetLabel(); if(SuperLabel.IsEmpty() && !IsExpanded()) { AutoGroupLabel = FText(); for(int32 Index = 0; Index < GetNumChildNodes(); Index++) { if(const FSchematicGraphNode* ChildNode = GetChildNode(Index)) { const FText& ChildLabel = ChildNode->GetLabel(); if(!ChildLabel.IsEmpty()) { if(!AutoGroupLabel.IsEmpty()) { AutoGroupLabel = FText::Format(LOCTEXT("AutoGroupLabelAppendFormat", "{0}\n{1}"), AutoGroupLabel, ChildLabel); } else { AutoGroupLabel = ChildLabel; } } } } return AutoGroupLabel; } return SuperLabel; } #undef LOCTEXT_NAMESPACE #endif