이번 구현의 목표는 인벤토리의 아이템을 클릭하면, 아이템 바로 옆에 사용 확인창을 띄워주는 것이었습니다.
그런데, 두 위젯은 서로 같은 Canvas 아래에 있지 않아서 위치를 어떻게 세팅해야할지 계산이 필요했습니다.

두 위젯간 연관성이 없기떄문에, 위젯에 의존적이지 않은 좌표계상에서 계산해서 그 위치로 세팅할 방법이 필요했고, 아래 순서로 처리할 수 있었습니다.
1. 아이템 칸의 위치를 얻고, 그 위치를 절대 좌표로 변환
const FGeometry& ItemGeometry = SourceItem->GetCachedGeometry();
const FVector2D ItemAbsolutePosition = ItemGeometry.GetAbsolutePosition();
const FVector2D ItemAbsoluteSize = ItemGeometry.GetAbsoluteSize();
const FVector2D TargetAbsoluteLocation = FVector2D(
ItemAbsolutePosition.X + ItemAbsoluteSize.X,
ItemAbsolutePosition.Y);
const FGeometry& ParentGeometry = MenuPanel->GetParent()->GetCachedGeometry();
const FVector2D TargetLocalPosition = ParentGeometry.AbsoluteToLocal(TargetAbsoluteLocation);
MenuPanel->SetRenderTranslation(TargetAbsoluteLocation);
위 코드를 적용한 결과, 두번째 호출부터 위치가 정상적으로 잘 표시 되었습니다. 첫번째 호출시에는 MenuPanel->GetParent()에 해당하는 위젯이 한번도 실제 스크린 상에 그려진 적이 없어서 아직 스크린상에 표현될 Geometry가 어떤지 모르는 상태이기 때문입니다. 처음으로 UI에 그려지기 전 Geometry의 정보를 보면 Scale=1, Position = (0,0) 등 기본값이 들어있는 걸 볼 수 있었습니다.
이 문제는 그냥 1틱을 더 쓰는 것으로 쉽게 해결했습니다.
// 우선 Geometry가 세팅되도록 화면에 표시
SetVisibility(ESlateVisibility::Visible);
// MenuPanel은 위치 계산이 안되었으므로 아직 표시하지 않음
MenuPanel->SetVisibility(ESlateVisibility::Hidden);
// 화면에 그려지기 위해 1틱 대기
co_await UE5Coro::Latent::NextTick();
// 다음틱에서 메뉴 패널 위치 계산
const FGeometry& ParentGeometry = MenuPanel->GetParent()->GetCachedGeometry();
const FVector2D TargetLocalPosition = ParentGeometry.AbsoluteToLocal(TargetAbsoluteLocation);
MenuPanel->SetRenderTranslation(TargetLocalPosition);
// 위치 세팅이 끝났으니 표시 가능
MenuPanel->SetVisibility(ESlateVisibility::Visible);
여기서 더 나아가서 생각하면 창이 떠있는 상태에서 화면 사이즈가 바뀔 수도 있고, 1틱을 기다리는 것도 아까우니 미리 계산도 가능할 방법도 있을 것 같고, 여러 생각을 해보고 그걸 코드에 적용해볼 수도 있어 보입니다.
render space상이라는 걸 의미하는 단어입니다. AbsolutePosition이면 render space상에서의 위젯 위치, AbsoluteSize이면 render space상에서의 위젯 크기를 의미합니다.
Get the absolute position in render space.
특정 Geometry상이라는 걸 의미하는 단어입니다.
위젯의 좌표계를 표현할 때 사용합니다. UWidget::GetCachedGeometry로 얻어올 수 있습니다.
Size, Scale, Position, AccumulatedRenderTransform 정보를 가지고 있습니다.
UWidget은 UPanelSlot타입의 Slot 속성을 가지고 있습니다. 위젯이 어떤 Panel에 속해있는 경우, 해당 Panel상에서의 위젯 위치 등의 정보가 들어있습니다. UPanelSlot에는 기능이 거의 없어 부모가되는 Panel의 타입을 아는 경우에 캐스팅해서 정보를 읽고 쓸 수 있습니다. 에디터에서는 Detail패널의 Slot 부분에 해당하는 정보입니다.

Offset을 조정하는 함수입니다. 해당 Widget이 UCanvas의 자식인 경우에만 사용할 수 있으며 에디터에서 아래 부분을 수정하는 것과 동일한 효과입니다.
Cast<UCanvasPanelSlot>(Widget->Slot)->SetPosition()
RenderTransform.Translation을 조정하는 함수입니다. 모든 위젯에 공통으로 있는 속성으로, 에디터의 아래 부분을 수정하는 것과 동일한 효과입니다.

이번에는 화면의 특정 위치에 UI를 띄운다라는 간단한 목표를 위해서 하루종일 코드를 봤더니 알게되는 게 조금 있었던 것 같습니다. 위젯에서 슬롯이 어떤 개념인지, 각 위젯들의 위치 계산은 어떤 식으로 이루어지고 있는지 조금은 알 수 있게 되었네요. 그리고 이 과정에서 AI는 거의 도움이 되지 않았습니다... 에디터상에서 각 위젯들이 어떤 식으로 연결되어 있는지, 어떤 시점에 UI가 뜨는지를 몰라서 그런지, 전혀 동작하지 않는 코드를 줘서 공식문서랑 코드를 보면서 동작을 파악하고, 디버거를 붙여서 값을 확인해가면서 수정했습니다.
다음에는 UI의 Navigation관련 동작에 대해서 써 볼 예정입니다.