October 3, 2018

Rich Text Block 을 사용한 고급 텍스트 스타일링

저자: Cody Albert

게임 UI 제작에 필요한 다양한 텍스트 블록 스타일과 사용자 정의 옵션은 기본적으로 UMG 에서 제공하고 있습니다. 하지만 텍스트의 스타일 변경, 이미지 삽입, 하이퍼링크 등 보다 유연한 마크업 지원이 필요한 경우도 많았으며, 그 대부분은 코드를 통해 Rich Text Block (리치 텍스트 블럭) 실험단계 위젯으로 가능했습니다.

4.20 릴리즈에서는 이 위젯을 UMG 에서 사용할 수 있도록 하여, 워크플로의 유연성과 확장성을 개선했습니다. 이 개선 단계의 일환으로 개발자가 필요한 모든 사용자 정의 기능을 지원하기 보다는 Rich Text Block 이 Decorator (데코레이터) 클래스를 받아 프로젝트에 필요한 마크업 작동방식을 정의할 수 있도록 구성했습니다. Decorator 클래스 예제는 RichTextBlockImageDecorator.cpp 에서 찾을 수 있습니다.

이 블로그 글에서는 UI 디자이너와 프로그래머 입장에서 UMG 의 새로운 Rich Text Block 위젯을 사용하는 법에 대해 살펴보겠습니다. Decorator 클래스로 추가 기능을 확장하는 법을 설명합니다. 사용자 정의 기능을 추가하기 전 먼저 새로 UMG 에 노출된 Rich Text Block 기능에 익숙해 지는 것이 좋습니다. Rich Text Block 위젯은 데이터 테이블(Data Table) 애셋 또는 별도의 Decorator 클래스로 정의한 텍스트 스타일과 데코레이터를 통해 블록의 내용을 사용자 정의할 수 있습니다.

데이터 테이블 애셋을 만들어 사용자 정의 구조체 기반 데이터 유형을 저장할 수 있습니다. 여기에는 Text Style Row (텍스트 스타일 행)과 Image Row (이미지 행) 두 구조체가 제공됩니다. Text Style Row 구조체는 Rich Text Block 에 제공되는 내장 스타일의 일부이며 폰트 유형, 윤곽선, 색과 크기 등을 정의할 수 있습니다. Image Row 구조체는 RichTextBlockImageDecorator 예제 클래스에 제공되는 일부이며 Rich Text Block 위젯의 Decorator 클래스를 지정할 수 있습니다. Text Style Row 구조체와 마찬가지로 크기 스케일, 색조, 정렬과 같은 삽입 이미지의 프로퍼티를 정의할 수 있습니다.

RichTextBlockImageDecorator 클래스 예제에는 별도의 마크업을 만들 수 있는 템플릿이 제공되므로, 이 부분을 원하는 Slate (슬레이트) 콘텐츠로 대체하여 이미지, 하이퍼링크는 물론 전체 위젯까지도 넣을 수 있습니다! 데이터 테이블은 어떤 데이터 유형도 저장할 수 있으며, 에디터에서 데이터 테이블 애셋으로 설정할 수 있습니다.

시작하기

우선 새 위젯 블루프린트를 만들고 팔레트 창에서 Rich Text Block 을 끌어 Canvas 에 놓습니다. Rich Text Block 을 선택한 채 디테일 패널의 Text Styles Set 를 찾습니다. 이 애셋 할당 슬롯에 스타일 데이터 테이블을 지정하면 원하는 텍스트 스타일은 물론 앞으로 사용할 수도 있는 추가 스타일을 얼마든지 정의할 수 있습니다. 계속해서 이 할당 드롭다운을 선택하고 Data Table (데이터 테이블)을 선택하거나 콘텐츠 브라우저에서 신규 추가 > 기타 > 데이터 테이블을 선택하여 새 데이터 테이블을 만듭니다.
Rich-Text-Block_1.png

데이터 테이블을 만들 때, UMG 의 디테일 패널에서 계속 만들어도 됩니다. Pick Structure (구조체 선택) 창과 드롭다운에서 행 구조체에 Rich Text Style Row 를 선택합니다.
Rich-Text-Block_2.png

UMG 의 디테일 패널에서 또는 콘텐츠 브라우저에서 새 데이터 테이블을 더블클릭하여 엽니다. 데이터 테이블 에디터에서 “Default” 라는 행을 새로 만드는 것으로 시작합니다. 이 행은 기본 상태의 텍스트를 나타내며, 다른 텍스트 스타일을 명시하지 않은 경우 Rich Text Block 에 자동 사용됩니다.
Rich-Text-Block_3.png

새로 만든 Default 행 아래 다른 옵션을 살펴보고, Font Family, Size, Typeface 와 같은 기본 스타일을 설정합니다. 다 됐으면 더하기 (+) 버튼을 눌러 새 행을 추가한 뒤 Row Name 글상자에 이름을 입력하여 스타일을 조금 추가합니다.

데이터 테이블 애셋을 할당한 위젯 블루프린트로 돌아와, 계속해서 디테일 패널을 통해 Rich Text Block 의 Text 섹션에 텍스트를 조금 추가합니다.
Rich-Text-Block_4.png

UMG 툴바에서 컴파일 버튼을 클릭해야 Rich Text Block 위젯에 텍스트가 표시될 수 있습니다.
Rich-Text-Block_5.png

여기 텍스트는 아까 설정한 Default 행을 사용합니다. 데이터 테이블 애셋에서 만든 다른 스타일을 적용할 때 사용하는 포맷은 다음과 같습니다.
<stylename>Text</stylename>
Rich-Text-Block_6.png

이 예제에서는 데이터 테이블 애셋의 행 rich 부분이 태그를 상속하도록 둘러쌌습니다. 이렇게 하면 설정해 둔 프로퍼티가 텍스트에 상속되어, 여기서처럼 주황 텍스트에 검정 윤곽선이 됩니다.

참고로 이 스타일 태그는 RichText.* 와 같은 접두사나 접미사가 필요치 않으며, 대소문자를 구분하지 않습니다.

데코레이터 사용하기

이제 Rich Text Block 안에 다양한 스타일을 적용할 수 있지만, 다른 텍스트를 삽입하려면 어떻게 할까요? 데코레이터를 사용하여 별도의 마크업 태그를 설정하면 됩니다. 이 마크업 태그로 텍스트 안에서 원하는 것을 무엇이든 자연스럽게 Slate (슬레이트)를 사용해 렌더링할 수 있습니다.

시작을 돕기 위해 제공한 예제 RichTextBlockImageDecorator 클래스에서 Decorator 클래스를 사용하여 Rich Text Block 에 이미지를 추가할 수 있습니다. Rich Text Style Row 의 내장 스타일처럼 Rich Image Row 구조체도 삽입 텍스트에 지원할 모든 이미지를 정의합니다.
Rich-Text-Block_7.png

이어서 제공된 RichTextBlockImageDecorator 클래스를 확장하여 서브클래스가 방금 만든 Rich Image Row 데이터 테이블을 지정하도록 하겠습니다. 가장 간단한 방법은 새 블루프린트 클래스를 만들고 부모 클래스로 제공된 RichTextBlockImageDecorator 클래스를 선택한 다음 그 블루프린트를 열고 클래스의 Image Set 프로퍼티에 데이터 테이블을 할당하는 것입니다.

참고로 4.20 에서 이미지 데코레이터는 부모 클래스 목록에 나타나지 않지만, 4.21 에서는 지원됩니다. 그동안 C++ 클래스로 확장한 뒤 C++ 파일에서 데이터 테이블을 할당하거나, 헤더 상단 UCLASS 매크로에 Blueprintable 을 추가하면 블루프린트로 서브클래스를 만들 수 있습니다.

데코레이터 설정이 완료되면, Rich Text Block 의 Decorator Classes 배열에 추가하고 다음 마크업을 사용하여 테이블에서 이미지를 삽입합니다.
<img id="ImageNameFromTable" />
변경 적용 및 표시를 위해서는 툴바의 컴파일 버튼을 클릭해야 할 수 있습니다.
Rich-Text-Block_8.png

새 데코레이터 추가하기

RichTextBlockImageDecorator 클래스를 예제로 제공하기는 하지만, Rich Text Block 의 가장 좋은 점은 별도의 커스텀 데코레이터 정의를 통해 슬레이트를 완벽 활용, 텍스트에 무엇이든 삽입할 수 있다는 점입니다. 이를 위해서는 URichTextBlockDecoratorFRichTextDecorator, 두 개의 클래스를 만들어야 합니다. 이 작업을 완료하면 UMG 에서 Rich Text Block 의 DecoratorClasses 배열을 통해 어떤 Rich Text Block 에도 데코레이터를 추가할 수 있게 됩니다.

URichTextBlockDecorator 는 에디터의 디테일 패널에 프로퍼티를 노출시킬 수 있는 UObject 클래스를 정의합니다. 최소한 CreateDecorator 는 구현해야 하는데, 그래야 모든 무거운 작업 처리를 위해 만드는 FRichTextDecorator 인스턴스로의 SharedPtr (공유 포인터)를 반환합니다. 여기서 얼마든지 다른 프로퍼티 및 유틸리티 함수를 구현하여, 디자이너가 Decorator 서브클래스를 블루프린트로 만들어 필요한 데이터를 전달하도록 할 수 있습니다. RichTextBlockImageDecorator 에 이미지 테이블을 전달할 수 있도록 데이터 테이블 프로퍼티를 정의한다고 했던 내용을 기억하시나요? 블루프린트에서 수정하려는 것은 여기 UObject 에 있어야 합니다.

FRichTextDecorator 는 마크업 태그의 실제 파싱/대체를 담당하며, 두 가지 함수를 구현해야 합니다. 첫 번째 함수 Supports 는 FTextRunParseResults 를 통해 마크업 태그 내용을 받아 단순히 그 데코레이터가 이 태그 처리를 실제 담당하는지 여부를 true / false 로 반환합니다. Supports 는 DecoratorClasses 배열의 모든 데코레이터에 대해 호출한 뒤 처리를 담당하는 데코레이터가 없으면 태그를 그냥 일반 텍스트로 표시하도록 예비 전환합니다. 두 번째 함수 CreateDecoratorWidget 를 호출하면 지원되는 마크업 태그를 대체하여 위젯을 실제 구성하고 반환합니다. 태그에 텍스트 또는 메타데이터가 필요하면 FTextRunInfo 에 액세스합니다.

RichTextBlockImageDecorator 클래스의 경우 SRichInlineImage 위젯을 정의하고 UObject 래퍼 클래스에 전달된 데이터 테이블에서 올바른 이미지로 채운 뒤 CreatorDecoratorWidget 반환값으로 전달합니다.

프로젝트에서 리치 텍스트 사용하기

Rich Text Block 의 내장 기능 사용법과 Decorator 클래스에 별도 기능을 추가하는 법을 살펴봤습니다. 이제 이것을 프로젝트의 워크플로에 어떻게 맞출까요?

Rich Text Block 을 만들 때마다 매번 Decorator Classes 배열에 똑같은 데코레이터 세트를 설정하는 경우, Rich Text 위젯 서브클래스에 기본 데코레이터 세트를 사용하면 유용할 수 있습니다. 더 많은 제어가 필요한 경우를 위해 SRich Text Block 는 커스텀 파서 (parser) 및 마샬러 (marshaller)도 지원합니다. 별도의 파서를 작성하여 마크업 태그 감지 및 처리 규칙을 변경하고, 커스텀 마샬러로 위젯 내 텍스트 배치 방식을 제어할 수 있습니다.

프로젝트의 모든 텍스트 부분에 Rich Text Block 을 사용하면 좋겠다 생각될 수 있지만, 태그를 검색할 때 텍스트 파싱에 관련된 퍼포먼스 비용이 발생합니다. 퍼포먼스가 중요한 상황이라면 Rich Text Block 의 추가 기능이 필수가 아닌 경우 일반 텍스트 블록을 사용하는 것이 좋습니다.

Rich Text Block 위젯은 프로젝트의 텍스트에 흥미로운 효과를 적용할 수 있는 가능성을 열어줍니다. 텍스트 강조 및 게임패드 버튼과 같은 단순한 효과는 물론 링크가 적용된 버튼같은 상효작용 효과를 적용할 수도 있고, 데코레이터를 통해 원하는 것은 무엇이든 추가할 수 있습니다!

Rich Text Block 문서에서 시작해 보세요!