// Fill out your copyright notice in the Description page of Project Settings. #include "SChannelNode.h" #include "MultiBoxBuilder.h" #include "SButton.h" #include "SChannelNodeButton.h" #include "SlateApplication.h" #include "SlateOptMacros.h" #include "SMenuAnchor.h" #include "SOverlay.h" #include "SSplitter.h" #include "STextBlock.h" #include "Singleton/MixerList.h" #include "Mixer/MixerTrack.h" #include "Widgets/SBoxPanel.h" BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION void SChannelNode::Construct(const FArguments& InArgs, FChannelNode* InChannelNode, FChannelInterface* InNodeOwner, int32 NodeNameIndex) { ChannelNode = InChannelNode; ChannelNodeType = InArgs._ChannelNodeType; NodeOwner = InNodeOwner; NodeIndex = NodeNameIndex; FText PortName = FText::FromString(GetNodeName(NodeNameIndex)); ChildSlot [ SNew(SHorizontalBox) +SHorizontalBox::Slot() .FillWidth(1) [ SAssignNew(PortTextBlock, STextBlock) .Text(PortName) ] +SHorizontalBox::Slot() .AutoWidth() [ SAssignNew(ChangeNodeButton, SButton) .OnClicked_Lambda([this]() { ShowNodeSelectMenu(); return FReply::Handled(); }) [ SAssignNew(NodeNameTextBlock, STextBlock) .Text(FText::FromString(ChannelNode->GetName())) ] ] ]; } void SChannelNode::ShowNodeSelectMenu() { FMenuBuilder MenuBuilder(true, nullptr); MenuBuilder.AddWidget( CreateNodeSelectMenu(), FText() ); auto Pos = ChangeNodeButton->GetTickSpaceGeometry().GetAbsolutePosition(); Pos.Y += ChangeNodeButton->GetTickSpaceGeometry().GetAbsoluteSize().Y; FSlateApplication::Get().PushMenu(SharedThis(this), FWidgetPath(), MenuBuilder.MakeWidget(), Pos, FPopupTransitionEffect::ComboButton); } TSharedRef SChannelNode::CreateNodeSelectMenu() { TSharedRef MenuBox = SNew(SVerticalBox); MenuBox->AddSlot() .AutoHeight() [ SNew(SChannelNodeButton, FNullChannelNode::Get()) .OnClickedDelegate(this, &SChannelNode::OnMenuNodeSelected) ]; FMixerList& MixerList = FMixerList::Get(); for (const FMixerTrack* Mixer : MixerList) { MenuBox->AddSlot() .AutoHeight() [ SNew(STextBlock) .Text(FText::FromString(Mixer->GetName())) ]; const TArray& MixerOutputNodes = Mixer->GetChannelInterface()->OutputChannelNodes; for (FChannelNode* MixerChannelNode : MixerOutputNodes) { MenuBox->AddSlot() .AutoHeight() [ SNew(SChannelNodeButton, MixerChannelNode) .OnClickedDelegate(this, &SChannelNode::OnMenuNodeSelected) ]; } } return MenuBox; } void SChannelNode::OnMenuNodeSelected(FChannelNode* Node) { check(NodeOwner); switch (ChannelNodeType) { case EChannelNodeType::InputNode: { NodeIndex = NodeOwner->GetInputNodeIndex(ChannelNode); NodeOwner->SetInputChannel(NodeIndex, Node); break; } case EChannelNodeType::OutputNode: { NodeIndex = NodeOwner->GetOutputNodeIndex(ChannelNode); NodeOwner->SetOutputChannel(NodeIndex, Node); break; } default: ; } ChannelNode = Node; NodeNameTextBlock->SetText(FText::FromString(Node->GetName())); } FString SChannelNode::GetNodeName(int32 NodeNameIndex) { FString PortName; TMap PortNames; switch (ChannelNodeType) { case EChannelNodeType::InputNode: PortNames = NodeOwner->GetInputChannelNodeName(ChannelNode); break; case EChannelNodeType::OutputNode: PortNames = NodeOwner->GetOutputChannelNodeName(ChannelNode); break; default: ; } const FName* NameA = PortNames.Find(NodeNameIndex); const FName* NameB = PortNames.Find(NodeNameIndex + 1); if (NameA && NameB) { if (*NameA == *NameB) PortName = NameA->ToString(); else PortName = FString::Printf(TEXT("%s-%s"), *NameA->ToString(), *NameB->ToString()); } else if (NameA) { PortName = NameA->ToString(); } else if (NameB) { PortName = NameB->ToString(); } else { PortName = TEXT("Null"); } return PortName; } END_SLATE_FUNCTION_BUILD_OPTIMIZATION