버튼이 1개, 혹은 2개 있는 팝업창을 띄워 해당 버튼들에 함수를 바인딩해야 하는 일은 아주 흔하다.
지금까지 쓴 방법은 BFL 써서 설명이나 버튼 텍스트, 색깔까진 간편하게 했는데.. 함수 바인드를 하는 과정이 번거로웠다.
만들어진 위젯에서 버튼 꺼내고 델리게이트까지 꺼내서 커스텀 이벤트 노드 붙이는 방법이었다.
노드 정리가 너무 힘들었다.
그래서 커스텀 노드를 만들기로 했다.
사용한 노드는 UK2Node_BaseAsyncTask다.
Proxy 클래스에 선언된 델리게이트를 자동으로 추적해 핀으로 뽑아주고, Proxy가 하는 일이 끝나면 해당 델리게이트가 호출되도록 만들어줄 수 있다.
// K2Node_CreatePopup.cpp
UK2Node_CreatePopup::UK2Node_CreatePopup(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
ProxyFactoryFunctionName = GET_FUNCTION_NAME_CHECKED(UPopupProxy, CreatePopupProxy);
ProxyFactoryClass = UPopupProxy::StaticClass();
ProxyClass = UPopupProxy::StaticClass();
}
// PopupProxy.cpp
UPopupProxy* UPopupProxy::CreatePopupProxy(
const UObject* WorldContextObject,
bool bHasSecondButton,
const FText Description,
FButtonStyleStruct FirstButtonStyle,
FButtonStyleStruct SecondButtonStyle)
{
UPopupProxy* Proxy = NewObject<UPopupProxy>();
Proxy->SetFlags(RF_StrongRefOnFrame);
Proxy->Popup(WorldContextObject, bHasSecondButton, Description, FirstButtonStyle, SecondButtonStyle);
return Proxy;
}
K2Node 클래스와 Proxy 클래스에 각각 함수를 선언, 연결해준다.
이제 노드가 호출되면 CreatePopupProxy가 호출된다.
여기서 중요한 건 GET_FUNCTION_NAME_CHECKED로 가져온 함수의 매개변수가 자동으로 노드에 나타난다는 점이다.
원한다면 매개변수에 UUserWidget*&를 함께 선언, Proxy의 Popup 함수에서 해당 매개변수에 만들어진 팝업을 넣어주면 블루프린트상에서 받아와 사용할 수 있다.
내친김에 커스텀 노드니까 핀도 맘대로 만들었다 지웠다 해봐야겠다.
// K2Node_CreatePopup.h
// 노드 새로고침할 때 호출되는 함수
virtual void ReconstructNode() override;
// Pin의 값이 변경될 때 호출되는 함수
virtual void PinDefaultValueChanged(UEdGraphPin* Pin) override;
// K2Node_CreatePopup.cpp
void UK2Node_CreatePopup::ReconstructNode()
{
Super::ReconstructNode();
// bHasSecondButton의 값 받아오기
bool bHasSecond = true;
if (UEdGraphPin* Pin = FindPin(TEXT("bHasSecondButton")))
{
bHasSecond = Pin->DefaultValue == TEXT("true");
}
// 값이 false인 경우 SecondButtonStyle 핀을 찾아 지운다
const FName PinNameToDelete = TEXT("SecondButtonStyle");
if (!bHasSecond)
{
if (UEdGraphPin* PinToDelete = FindPin(PinNameToDelete))
{
// 연결을 끊어주지 않고 삭제하면 크래쉬나는 경우 있으므로 주의
PinToDelete->BreakAllPinLinks();
Pins.Remove(PinToDelete);
}
PinNameToDelete = TEXT("SecondButtonClickedDelegate");
if (UEdGraphPin* PinToDelete = FindPin(PinNameToDelete))
{
PinToDelete->BreakAllPinLinks();
// 델리게이트와 연결된 핀이라서 제거할 경우 컴파일 에러 발생
PinToDelete->bHidden = true;
}
}
}
void UK2Node_CreatePopup::PinDefaultValueChanged(UEdGraphPin* Pin)
{
Super::PinDefaultValueChanged(Pin);
// bHasSecondButton의 값이 변경된 경우 새로고침 함수 호출
if (Pin->PinName == TEXT("bHasSecondButton"))
{
ReconstructNode();
if (UEdGraph* Graph = GetGraph())
{
Graph->Modify();
Graph->NotifyGraphChanged();
}
}
}
좌측의 Has Second Button을 조작하면 Second 관련 핀이 추가, 제거되는 걸 볼 수 있다.
노드 정리가 수월해질 것 같다.