1. Slate 서술형 문법 개요
Slate UI는 C++ 코드 안에서 위젯 트리를 함수 체이닝으로 선언하는 방식으로 구성함. 포인터 간접 접근(인디렉션) 없이도 위젯 레퍼런스를 곧바로 얻어 즉시 사용하거나 속성을 바인딩할 수 있음. 결과적으로 코드 가독성과 런타임 안정성 향상 효과를 가짐
// 인자 정의 예시
SLATE_BEGIN_ARGS(SSubMenuButton)
: _ShouldAppearHovered(false) {}
SLATE_ATTRIBUTE(FString, Label) // 버튼 라벨
SLATE_EVENT(FOnClicked, OnClicked) // 클릭 델리게이트
SLATE_NAMED_SLOT(FArguments, FSimpleSlot, Content) // 내부 콘텐츠
SLATE_ATTRIBUTE(bool, ShouldAppearHovered) // 호버 외관 여부
SLATE_END_ARGS()
2. 컴포지션 (Composition)
컴포지션은 SNew 매크로와 슬롯 대괄호 ([]
) 블록을 이용해 부모-자식 구조를 선언적으로 작성하는 방법. 모든 자식 위젯은 부모의 슬롯 안에 정의되며, 중첩을 통해 복잡한 UI 트리를 구성함
TSharedRef<SSubMenuButton> SubMenuButton =
SNew(SSubMenuButton)
.Label(FString(TEXT("서브 메뉴")))
.OnClicked(this, &SMyWidget::HandleSubMenuClicked)
.ShouldAppearHovered(true)
[
SNew(STextBlock)
.Text(FText::FromString(TEXT("내용")))
];
3. 스타일 (Style)
위젯별 속성 메서드(예: .ForegroundColor()
, .Font()
)로 즉석에서 스타일을 지정하거나, FSlateStyleSet을 전역 등록해 재사용 가능한 스타일 리소스를 정의함. 스타일은 위젯 장면 변경 없이도 스킨을 교체하는 패턴을 구현할 수 있음
SubMenuButton->SetForegroundColor(FLinearColor::Yellow);
4. 입력 (Input)
Slate 위젯은 델리게이트(예: FOnClicked, FOnKeyDown)를 통해 입력을 수신함. 델리게이트는 FReply
값을 반환해 Propagate 여부를 제어함. 또한 Enhanced Input 또는 Low-Level 키보드 루트를 통해 핫키 바인딩 가능
FReply SMyWidget::HandleSubMenuClicked()
{
DoSomething();
return FReply::Handled(); // 이벤트 소비
}
5. 출력 (Binding & Invalidate)
SLATE_ATTRIBUTE
로 선언한 속성은 람다 또는 TAttribute 바인딩을 통해 실시간으로 값을 제공함. 속성이 변경될 때 Invalidate(EInvalidateWidget::Layout)
또는 자동 Dirty 추적을 통해 랭더링을 재계산함
.Label(this, &SMyWidget::GetDynamicLabel) // 동적 라벨
6. 레이아웃 프리미티브 (Layout Primitives)
- SVerticalBox & SHorizontalBox - 박스 슬롯 에
.AutoHeight()
,.FillWidth()
등 비율 제어 가능함 - SOverlay - 위젯 겹치기 레이어 배치에 사용함
- SBox - 고정 Size 또는 Padding 지정에 편리함
- SUniformGridPanel - 표형 균등 그리드 구성 도움됨
7. 사용자 주도형 레이아웃
드래그 리사이즈, 스플리터, 앵커링 등을 통해 플레이어가 직접 패널을 배치할 수 있도록 SConstraintCanvas, SSplitter를 활용함. 상태 저장은 JSON 또는 INI 에 저장해 재시작 후 복원 작업 권장함
SAssignNew(Root, SSplitter)
+ SSplitter::Slot()
.Value(0.3f)
[
LeftPanel.ToSharedRef()
]
+ SSplitter::Slot()
.Value(0.7f)
[
RightPanel.ToSharedRef()
];
8. 전체 코드 스니펫 Workflow
아래 예시는 커스텀 버튼 클래스 구현부터 위젯 생성, 스타일 적용, 입력 바인딩을 통합 시연함
// 1) 헤더
class SSubMenuButton : public SCompoundWidget
{
public:
SLATE_BEGIN_ARGS(SSubMenuButton)
: _ShouldAppearHovered(false) {}
SLATE_ATTRIBUTE(FString, Label)
SLATE_EVENT(FOnClicked, OnClicked)
SLATE_NAMED_SLOT(FArguments, FSimpleSlot, Content)
SLATE_ATTRIBUTE(bool, ShouldAppearHovered)
SLATE_END_ARGS()
void Construct(const FArguments& InArgs);
private:
FReply HandleClick();
TAttribute<FString> Label;
bool bForceHover;
};
// 2) CPP
void SSubMenuButton::Construct(const FArguments& InArgs)
{
Label = InArgs._Label;
OnClicked = InArgs._OnClicked;
bForceHover = InArgs._ShouldAppearHovered;
ChildSlot
[
SNew(SButton)
.OnClicked(this, &SSubMenuButton::HandleClick)
[
SNew(STextBlock)
.Text_Lambda([this]{ return FText::FromString(Label.Get()); })
]
];
}
FReply SSubMenuButton::HandleClick()
{
return OnClicked.IsBound() ? OnClicked.Execute() : FReply::Unhandled();
}
// 3) 사용 측
SNew(SSubMenuButton)
.Label(TEXT("인벤토리"))
.ShouldAppearHovered(false)
.OnClicked(this, &SMyHudWidget::OpenInventory);
9. 요약
Slate 서술형 문법은 구조적 가독성, 런타임 안전성, 유연한 데이터 바인딩이라는 세 가치를 제공함. 컴포지션으로 트리를 선언하고, 스타일로 시각 통일감을 보장하며, 델리게이트와 속성 바인딩으로 입·출력을 명확히 관리하는 방법을 채택함. 레이아웃 프리미티브와 사용자 주도 레이아웃 패턴을 조합해 툴-라이크 UI를 효율적으로 구현할 수 있음