mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
ui2: port examine item dialog
This commit is contained in:
parent
c4ef88a058
commit
238fd19e4f
14 changed files with 208 additions and 323 deletions
|
@ -601,6 +601,7 @@
|
|||
"OSD_UNKNOWN_COMMAND": "Unknown command: %s",
|
||||
"OSD_WIREFRAME_MODE_OFF": "Wireframe mode: off",
|
||||
"OSD_WIREFRAME_MODE_ON": "Wireframe mode: on",
|
||||
"PAGINATION_NAV": "%d / %d",
|
||||
"PASSPORT_EXIT_DEMO": "Exit Demo",
|
||||
"PASSPORT_EXIT_GAME": "Exit Game",
|
||||
"PASSPORT_EXIT_TO_TITLE": "Exit to Title",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "game/ui/widgets/frame.h"
|
||||
|
||||
#include "game/text.h"
|
||||
#include "game/ui/widgets/spacer.h"
|
||||
#include "memory.h"
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#include "game/ui/widgets/spacer.h"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
typedef struct {
|
||||
UI_WIDGET_VTABLE vtable;
|
||||
int32_t width;
|
||||
int32_t height;
|
||||
} UI_SPACER;
|
||||
|
||||
static int32_t M_GetWidth(const UI_SPACER *self);
|
||||
static int32_t M_GetHeight(const UI_SPACER *self);
|
||||
static void M_SetPosition(UI_SPACER *self, int32_t x, int32_t y);
|
||||
static void M_Control(UI_SPACER *self);
|
||||
static void M_Free(UI_SPACER *self);
|
||||
|
||||
static int32_t M_GetWidth(const UI_SPACER *const self)
|
||||
{
|
||||
if (self->vtable.is_hidden) {
|
||||
return 0;
|
||||
}
|
||||
return self->width;
|
||||
}
|
||||
|
||||
static int32_t M_GetHeight(const UI_SPACER *const self)
|
||||
{
|
||||
if (self->vtable.is_hidden) {
|
||||
return 0;
|
||||
}
|
||||
return self->height;
|
||||
}
|
||||
|
||||
static void M_SetPosition(
|
||||
UI_SPACER *const self, const int32_t x, const int32_t y)
|
||||
{
|
||||
}
|
||||
|
||||
static void M_Free(UI_SPACER *const self)
|
||||
{
|
||||
Memory_Free(self);
|
||||
}
|
||||
|
||||
UI_WIDGET *UI_Spacer_Create(const int32_t width, const int32_t height)
|
||||
{
|
||||
UI_SPACER *const self = Memory_Alloc(sizeof(UI_SPACER));
|
||||
self->vtable = (UI_WIDGET_VTABLE) {
|
||||
.control = nullptr,
|
||||
.draw = nullptr,
|
||||
.get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth,
|
||||
.get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight,
|
||||
.set_position = (UI_WIDGET_SET_POSITION)M_SetPosition,
|
||||
.free = (UI_WIDGET_FREE)M_Free,
|
||||
};
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
return (UI_WIDGET *)self;
|
||||
}
|
144
src/libtrx/game/ui2/dialogs/examine_item.c
Normal file
144
src/libtrx/game/ui2/dialogs/examine_item.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
#include "game/ui2/dialogs/examine_item.h"
|
||||
|
||||
#include "game/game_string.h"
|
||||
#include "game/input.h"
|
||||
#include "game/sound.h"
|
||||
#include "game/text.h"
|
||||
#include "game/ui2/elements/anchor.h"
|
||||
#include "game/ui2/elements/frame.h"
|
||||
#include "game/ui2/elements/label.h"
|
||||
#include "game/ui2/elements/modal.h"
|
||||
#include "game/ui2/elements/pad.h"
|
||||
#include "game/ui2/elements/resize.h"
|
||||
#include "game/ui2/elements/spacer.h"
|
||||
#include "game/ui2/elements/stack.h"
|
||||
#include "memory.h"
|
||||
#include "strings.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define TITLE_MARGIN 5.0f
|
||||
#define WINDOW_MARGIN 10.0f
|
||||
#define DIALOG_PADDING 8.0f
|
||||
#define PADDING_SCALED (3.5f * (DIALOG_PADDING + WINDOW_MARGIN))
|
||||
|
||||
static bool M_SelectPage(UI2_EXAMINE_ITEM_STATE *state, int32_t new_page);
|
||||
|
||||
static bool M_SelectPage(
|
||||
UI2_EXAMINE_ITEM_STATE *const state, const int32_t new_page)
|
||||
{
|
||||
if (new_page == state->current_page || new_page < 0
|
||||
|| new_page >= state->page_content->count) {
|
||||
return false;
|
||||
}
|
||||
state->current_page = new_page;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UI2_ExamineItem_Init(
|
||||
UI2_EXAMINE_ITEM_STATE *const state, const char *const title,
|
||||
const char *const text, size_t max_lines)
|
||||
{
|
||||
state->current_page = 0;
|
||||
state->title = String_ToUpper(title);
|
||||
|
||||
const char *wrapped =
|
||||
String_WordWrap(text, Text_GetMaxLineLength() - PADDING_SCALED);
|
||||
state->page_content = String_Paginate(wrapped, max_lines);
|
||||
state->is_empty = String_IsEmpty(text);
|
||||
Memory_FreePointer(&wrapped);
|
||||
|
||||
// Compute actual maximum number of lines on any single page, which can be
|
||||
// less than the line cap.
|
||||
size_t max_vis_lines = 0;
|
||||
for (int32_t i = 0; i < state->page_content->count; i++) {
|
||||
size_t page_lines = 1;
|
||||
const char *c = *(char **)Vector_Get(state->page_content, i);
|
||||
while (*c != '\0') {
|
||||
page_lines += *c++ == '\n';
|
||||
}
|
||||
CLAMPL(max_vis_lines, page_lines);
|
||||
}
|
||||
state->max_lines = max_vis_lines;
|
||||
}
|
||||
|
||||
void UI2_ExamineItem_Control(UI2_EXAMINE_ITEM_STATE *const state)
|
||||
{
|
||||
const int32_t page_shift =
|
||||
g_InputDB.menu_left ? -1 : (g_InputDB.menu_right ? 1 : 0);
|
||||
if (M_SelectPage(state, state->current_page + page_shift)) {
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
}
|
||||
}
|
||||
|
||||
void UI2_ExamineItem_Free(UI2_EXAMINE_ITEM_STATE *const state)
|
||||
{
|
||||
Memory_FreePointer(&state->title);
|
||||
for (int32_t i = state->page_content->count - 1; i >= 0; i--) {
|
||||
char *const page = *(char **)Vector_Get(state->page_content, i);
|
||||
Memory_Free(page);
|
||||
}
|
||||
Vector_Free(state->page_content);
|
||||
}
|
||||
|
||||
void UI2_ExamineItem(UI2_EXAMINE_ITEM_STATE *const state)
|
||||
{
|
||||
if (state->is_empty) {
|
||||
return;
|
||||
}
|
||||
|
||||
UI2_BeginModal(0.5f, 0.5f);
|
||||
UI2_BeginFrame(UI2_FRAME_DIALOG_BACKGROUND);
|
||||
UI2_BeginPad(DIALOG_PADDING, DIALOG_PADDING);
|
||||
UI2_BeginStackEx((UI2_STACK_SETTINGS) {
|
||||
.orientation = UI2_STACK_VERTICAL,
|
||||
.align = { .h = UI2_STACK_H_ALIGN_SPAN },
|
||||
});
|
||||
|
||||
UI2_BeginAnchor(0.5f, 0.5f);
|
||||
UI2_Label(state->title);
|
||||
UI2_EndAnchor();
|
||||
UI2_Spacer(TITLE_MARGIN, TITLE_MARGIN);
|
||||
|
||||
for (int32_t i = 0; i < state->page_content->count; i++) {
|
||||
if (i != state->current_page) {
|
||||
UI2_BeginResize(-1.0f, 0.0f);
|
||||
} else if (state->page_content->count == 1) {
|
||||
UI2_BeginResize(-1.0f, -1.0f);
|
||||
} else {
|
||||
UI2_BeginResize(-1.0f, TEXT_HEIGHT_FIXED * state->max_lines);
|
||||
}
|
||||
UI2_Label(*(char **)Vector_Get(state->page_content, i));
|
||||
UI2_EndResize();
|
||||
}
|
||||
|
||||
if (state->page_content->count > 1) {
|
||||
UI2_Spacer(TITLE_MARGIN, TITLE_MARGIN * 3);
|
||||
|
||||
UI2_BeginAnchor(1.0f, 0.5f);
|
||||
UI2_BeginStack(UI2_STACK_HORIZONTAL);
|
||||
|
||||
if (state->current_page > 0) {
|
||||
UI2_Label("\\{button left} ");
|
||||
}
|
||||
|
||||
char page_indicator[100];
|
||||
sprintf(
|
||||
page_indicator, GS(PAGINATION_NAV), state->current_page + 1,
|
||||
state->page_content->count);
|
||||
UI2_Label(page_indicator);
|
||||
|
||||
if (state->current_page < state->page_content->count - 1) {
|
||||
UI2_Label(" \\{button right}");
|
||||
}
|
||||
|
||||
UI2_EndStack();
|
||||
UI2_EndAnchor();
|
||||
}
|
||||
|
||||
UI2_EndStack();
|
||||
UI2_EndPad();
|
||||
UI2_EndFrame();
|
||||
UI2_EndModal();
|
||||
}
|
|
@ -140,3 +140,4 @@ GS_DEFINE(DETAIL_FOG_END, "Fog end")
|
|||
GS_DEFINE(DETAIL_WATER_COLOR_R, "Water color (R)")
|
||||
GS_DEFINE(DETAIL_WATER_COLOR_G, "Water color (G)")
|
||||
GS_DEFINE(DETAIL_WATER_COLOR_B, "Water color (B)")
|
||||
GS_DEFINE(PAGINATION_NAV, "%d / %d")
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "./base.h"
|
||||
|
||||
UI_WIDGET *UI_Spacer_Create(int32_t width, int32_t height);
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "./ui2/common.h"
|
||||
#include "./ui2/dialogs/examine_item.h"
|
||||
#include "./ui2/dialogs/photo_mode.h"
|
||||
#include "./ui2/elements/anchor.h"
|
||||
#include "./ui2/elements/fade.h"
|
||||
|
|
22
src/libtrx/include/libtrx/game/ui2/dialogs/examine_item.h
Normal file
22
src/libtrx/include/libtrx/game/ui2/dialogs/examine_item.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include "../../../vector.h"
|
||||
#include "../common.h"
|
||||
|
||||
// A widget to cycle through several pages of a text content.
|
||||
|
||||
typedef struct {
|
||||
char *title;
|
||||
size_t max_lines;
|
||||
int32_t current_page;
|
||||
VECTOR *page_content;
|
||||
bool is_empty;
|
||||
} UI2_EXAMINE_ITEM_STATE;
|
||||
|
||||
void UI2_ExamineItem_Init(
|
||||
UI2_EXAMINE_ITEM_STATE *state, const char *title, const char *text,
|
||||
size_t max_lines);
|
||||
void UI2_ExamineItem_Control(UI2_EXAMINE_ITEM_STATE *state);
|
||||
void UI2_ExamineItem_Free(UI2_EXAMINE_ITEM_STATE *state);
|
||||
|
||||
void UI2_ExamineItem(UI2_EXAMINE_ITEM_STATE *state);
|
|
@ -206,10 +206,10 @@ sources = [
|
|||
'game/ui/widgets/frame.c',
|
||||
'game/ui/widgets/label.c',
|
||||
'game/ui/widgets/requester.c',
|
||||
'game/ui/widgets/spacer.c',
|
||||
'game/ui/widgets/stack.c',
|
||||
'game/ui/widgets/window.c',
|
||||
'game/ui2/common.c',
|
||||
'game/ui2/dialogs/examine_item.c',
|
||||
'game/ui2/dialogs/photo_mode.c',
|
||||
'game/ui2/elements/anchor.c',
|
||||
'game/ui2/elements/fade.c',
|
||||
|
|
|
@ -57,4 +57,3 @@ GS_DEFINE(OSD_DOOR_CLOSE, "Close Sesame!")
|
|||
GS_DEFINE(OSD_DOOR_OPEN_FAIL, "No doors in Lara's proximity")
|
||||
GS_DEFINE(ITEM_EXAMINE_ROLE, "\\{button empty} %s: Examine")
|
||||
GS_DEFINE(ITEM_USE_ROLE, "\\{button empty} %s: Use")
|
||||
GS_DEFINE(PAGINATION_NAV, "%d / %d")
|
||||
|
|
|
@ -1,21 +1,38 @@
|
|||
#include "game/option/option_examine.h"
|
||||
|
||||
#include "game/input.h"
|
||||
#include "game/ui/widgets/paginator.h"
|
||||
|
||||
#include <libtrx/game/objects/names.h>
|
||||
#include <libtrx/game/ui/common.h>
|
||||
#include <libtrx/game/ui2.h>
|
||||
|
||||
#define MAX_LINES 10
|
||||
|
||||
static UI_WIDGET *m_PaginatorUI = nullptr;
|
||||
typedef struct {
|
||||
struct {
|
||||
bool is_ready;
|
||||
UI2_EXAMINE_ITEM_STATE state;
|
||||
} ui;
|
||||
} M_PRIV;
|
||||
|
||||
static void M_End(void);
|
||||
static M_PRIV m_Priv = {};
|
||||
|
||||
static void M_End(void)
|
||||
static void M_Init(M_PRIV *p, GAME_OBJECT_ID obj_id);
|
||||
static void M_Shutdown(M_PRIV *p);
|
||||
|
||||
static void M_Init(M_PRIV *const p, const GAME_OBJECT_ID obj_id)
|
||||
{
|
||||
m_PaginatorUI->free(m_PaginatorUI);
|
||||
m_PaginatorUI = nullptr;
|
||||
p->ui.is_ready = true;
|
||||
UI2_ExamineItem_Init(
|
||||
&p->ui.state, Object_GetName(obj_id), Object_GetDescription(obj_id),
|
||||
MAX_LINES);
|
||||
}
|
||||
|
||||
static void M_Shutdown(M_PRIV *const p)
|
||||
{
|
||||
if (p->ui.is_ready) {
|
||||
UI2_ExamineItem_Free(&p->ui.state);
|
||||
p->ui.is_ready = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Option_Examine_CanExamine(const GAME_OBJECT_ID obj_id)
|
||||
|
@ -25,37 +42,37 @@ bool Option_Examine_CanExamine(const GAME_OBJECT_ID obj_id)
|
|||
|
||||
bool Option_Examine_IsActive(void)
|
||||
{
|
||||
return m_PaginatorUI != nullptr;
|
||||
const M_PRIV *const p = &m_Priv;
|
||||
return p->ui.is_ready;
|
||||
}
|
||||
|
||||
void Option_Examine_Control(const GAME_OBJECT_ID obj_id, const bool is_busy)
|
||||
{
|
||||
M_PRIV *const p = &m_Priv;
|
||||
if (is_busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_PaginatorUI == nullptr) {
|
||||
m_PaginatorUI = UI_Paginator_Create(
|
||||
Object_GetName(obj_id), Object_GetDescription(obj_id), MAX_LINES);
|
||||
if (!p->ui.is_ready) {
|
||||
M_Init(p, obj_id);
|
||||
}
|
||||
|
||||
m_PaginatorUI->control(m_PaginatorUI);
|
||||
UI2_ExamineItem_Control(&p->ui.state);
|
||||
|
||||
if (g_InputDB.menu_back || g_InputDB.menu_confirm) {
|
||||
M_End();
|
||||
M_Shutdown(p);
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Examine_Draw(void)
|
||||
{
|
||||
if (m_PaginatorUI != nullptr) {
|
||||
m_PaginatorUI->draw(m_PaginatorUI);
|
||||
M_PRIV *const p = &m_Priv;
|
||||
if (p->ui.is_ready) {
|
||||
UI2_ExamineItem(&p->ui.state);
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Examine_Shutdown(void)
|
||||
{
|
||||
if (m_PaginatorUI != nullptr) {
|
||||
M_End();
|
||||
}
|
||||
M_PRIV *const p = &m_Priv;
|
||||
M_Shutdown(p);
|
||||
}
|
||||
|
|
|
@ -1,232 +0,0 @@
|
|||
#include "game/ui/widgets/paginator.h"
|
||||
|
||||
#include "game/game_string.h"
|
||||
#include "game/input.h"
|
||||
#include "game/screen.h"
|
||||
#include "game/sound.h"
|
||||
#include "game/text.h"
|
||||
|
||||
#include <libtrx/game/ui/common.h>
|
||||
#include <libtrx/game/ui/widgets/label.h>
|
||||
#include <libtrx/game/ui/widgets/spacer.h>
|
||||
#include <libtrx/game/ui/widgets/stack.h>
|
||||
#include <libtrx/game/ui/widgets/window.h>
|
||||
#include <libtrx/memory.h>
|
||||
#include <libtrx/strings/common.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define TITLE_MARGIN 5
|
||||
#define WINDOW_MARGIN 10
|
||||
#define DIALOG_PADDING 5
|
||||
#define PADDING_SCALED (3.5 * (DIALOG_PADDING + WINDOW_MARGIN))
|
||||
|
||||
typedef struct {
|
||||
UI_WIDGET_VTABLE vtable;
|
||||
UI_WIDGET *window;
|
||||
UI_WIDGET *outer_stack;
|
||||
UI_WIDGET *bottom_stack;
|
||||
UI_WIDGET *title;
|
||||
UI_WIDGET *top_spacer;
|
||||
UI_WIDGET *text;
|
||||
UI_WIDGET *bottom_spacer;
|
||||
UI_WIDGET *left_arrow;
|
||||
UI_WIDGET *right_arrow;
|
||||
UI_WIDGET *right_arrow_spacer;
|
||||
UI_WIDGET *page_label;
|
||||
int32_t current_page;
|
||||
VECTOR *page_content;
|
||||
bool shown;
|
||||
} UI_PAGINATOR;
|
||||
|
||||
static void M_DoLayout(UI_PAGINATOR *self);
|
||||
static int32_t M_GetWidth(const UI_PAGINATOR *self);
|
||||
static int32_t M_GetHeight(const UI_PAGINATOR *self);
|
||||
static void M_SetPosition(UI_PAGINATOR *self, int32_t x, int32_t y);
|
||||
static bool M_SelectPage(UI_PAGINATOR *const self, int32_t new_page);
|
||||
static void M_Control(UI_PAGINATOR *self);
|
||||
static void M_Draw(UI_PAGINATOR *self);
|
||||
static void M_Free(UI_PAGINATOR *self);
|
||||
|
||||
static void M_DoLayout(UI_PAGINATOR *const self)
|
||||
{
|
||||
M_SetPosition(
|
||||
self, (Screen_GetResWidthDownscaled(RSR_TEXT) - M_GetWidth(self)) / 2.0,
|
||||
(Screen_GetResHeightDownscaled(RSR_TEXT) - M_GetHeight(self)) / 2.0);
|
||||
}
|
||||
|
||||
static int32_t M_GetWidth(const UI_PAGINATOR *const self)
|
||||
{
|
||||
return self->window->get_width(self->window);
|
||||
}
|
||||
|
||||
static int32_t M_GetHeight(const UI_PAGINATOR *const self)
|
||||
{
|
||||
return self->window->get_height(self->window);
|
||||
}
|
||||
|
||||
static void M_SetPosition(UI_PAGINATOR *const self, int32_t x, int32_t y)
|
||||
{
|
||||
self->window->set_position(self->window, x, y);
|
||||
}
|
||||
|
||||
static bool M_SelectPage(UI_PAGINATOR *const self, const int32_t new_page)
|
||||
{
|
||||
if (new_page == self->current_page || new_page < 0
|
||||
|| new_page >= self->page_content->count) {
|
||||
return false;
|
||||
}
|
||||
|
||||
self->current_page = new_page;
|
||||
UI_Label_ChangeText(
|
||||
self->text,
|
||||
*(char **)Vector_Get(self->page_content, self->current_page));
|
||||
|
||||
char page_indicator[100];
|
||||
sprintf(
|
||||
page_indicator, GS(PAGINATION_NAV), self->current_page + 1,
|
||||
self->page_content->count);
|
||||
UI_Label_ChangeText(self->page_label, page_indicator);
|
||||
UI_Label_SetVisible(self->left_arrow, self->current_page > 0);
|
||||
UI_Label_SetVisible(
|
||||
self->right_arrow, self->current_page < self->page_content->count - 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void M_Control(UI_PAGINATOR *const self)
|
||||
{
|
||||
const int32_t page_shift =
|
||||
g_InputDB.menu_left ? -1 : (g_InputDB.menu_right ? 1 : 0);
|
||||
if (M_SelectPage(self, self->current_page + page_shift)) {
|
||||
Sound_Effect(SFX_MENU_PASSPORT, nullptr, SPM_ALWAYS);
|
||||
}
|
||||
|
||||
if (self->window->control != nullptr) {
|
||||
self->window->control(self->window);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_Draw(UI_PAGINATOR *const self)
|
||||
{
|
||||
if (self->shown && self->window->draw != nullptr) {
|
||||
self->window->draw(self->window);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_Free(UI_PAGINATOR *const self)
|
||||
{
|
||||
for (int32_t i = self->page_content->count - 1; i >= 0; i--) {
|
||||
char *const page = *(char **)Vector_Get(self->page_content, i);
|
||||
Memory_Free(page);
|
||||
}
|
||||
Vector_Free(self->page_content);
|
||||
|
||||
self->text->free(self->text);
|
||||
self->top_spacer->free(self->top_spacer);
|
||||
self->title->free(self->title);
|
||||
if (self->bottom_stack != nullptr) {
|
||||
self->bottom_spacer->free(self->bottom_spacer);
|
||||
self->left_arrow->free(self->left_arrow);
|
||||
self->right_arrow->free(self->right_arrow);
|
||||
self->right_arrow_spacer->free(self->right_arrow_spacer);
|
||||
self->page_label->free(self->page_label);
|
||||
self->bottom_stack->free(self->bottom_stack);
|
||||
}
|
||||
self->outer_stack->free(self->outer_stack);
|
||||
self->window->free(self->window);
|
||||
Memory_Free(self);
|
||||
}
|
||||
|
||||
UI_WIDGET *UI_Paginator_Create(
|
||||
const char *const title, const char *const text, const int32_t max_lines)
|
||||
{
|
||||
UI_PAGINATOR *const self = Memory_Alloc(sizeof(UI_PAGINATOR));
|
||||
self->vtable = (UI_WIDGET_VTABLE) {
|
||||
.control = (UI_WIDGET_CONTROL)M_Control,
|
||||
.draw = (UI_WIDGET_DRAW)M_Draw,
|
||||
.get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth,
|
||||
.get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight,
|
||||
.set_position = (UI_WIDGET_SET_POSITION)M_SetPosition,
|
||||
.free = (UI_WIDGET_FREE)M_Free,
|
||||
};
|
||||
|
||||
self->shown = !String_IsEmpty(text);
|
||||
|
||||
self->outer_stack = UI_Stack_Create(
|
||||
UI_STACK_LAYOUT_VERTICAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE);
|
||||
|
||||
const char *upper_title = String_ToUpper(title);
|
||||
self->title =
|
||||
UI_Label_Create(upper_title, UI_LABEL_AUTO_SIZE, TEXT_HEIGHT_FIXED);
|
||||
Memory_FreePointer(&upper_title);
|
||||
UI_Stack_AddChild(self->outer_stack, self->title);
|
||||
|
||||
self->top_spacer = UI_Spacer_Create(TITLE_MARGIN, TITLE_MARGIN);
|
||||
UI_Stack_AddChild(self->outer_stack, self->top_spacer);
|
||||
|
||||
const char *wrapped =
|
||||
String_WordWrap(text, Text_GetMaxLineLength() - PADDING_SCALED);
|
||||
self->page_content = String_Paginate(wrapped, max_lines);
|
||||
self->current_page = 0;
|
||||
Memory_FreePointer(&wrapped);
|
||||
|
||||
self->text = UI_Label_Create(
|
||||
*(char **)Vector_Get(self->page_content, 0), UI_LABEL_AUTO_SIZE,
|
||||
UI_LABEL_AUTO_SIZE);
|
||||
UI_Stack_AddChild(self->outer_stack, self->text);
|
||||
|
||||
if (self->page_content->count > 1) {
|
||||
self->bottom_spacer = UI_Spacer_Create(TITLE_MARGIN, TITLE_MARGIN * 3);
|
||||
UI_Stack_AddChild(self->outer_stack, self->bottom_spacer);
|
||||
|
||||
self->bottom_stack = UI_Stack_Create(
|
||||
UI_STACK_LAYOUT_HORIZONTAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE);
|
||||
UI_Stack_AddChild(self->outer_stack, self->bottom_stack);
|
||||
|
||||
self->left_arrow =
|
||||
UI_Label_Create("\\{button left}", 22, TEXT_HEIGHT_FIXED);
|
||||
self->right_arrow =
|
||||
UI_Label_Create("\\{button right}", 16, TEXT_HEIGHT_FIXED);
|
||||
self->right_arrow_spacer = UI_Spacer_Create(6, TEXT_HEIGHT_FIXED);
|
||||
self->page_label =
|
||||
UI_Label_Create("", UI_LABEL_AUTO_SIZE, UI_LABEL_AUTO_SIZE);
|
||||
UI_Stack_AddChild(self->bottom_stack, self->left_arrow);
|
||||
UI_Stack_AddChild(self->bottom_stack, self->page_label);
|
||||
UI_Stack_AddChild(self->bottom_stack, self->right_arrow_spacer);
|
||||
UI_Stack_AddChild(self->bottom_stack, self->right_arrow);
|
||||
|
||||
UI_Stack_SetHAlign(self->bottom_stack, UI_STACK_H_ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
self->window = UI_Window_Create(
|
||||
self->outer_stack, DIALOG_PADDING, DIALOG_PADDING, DIALOG_PADDING * 2,
|
||||
DIALOG_PADDING);
|
||||
|
||||
// Ensure minimum width for page navigation as text content may be empty.
|
||||
int32_t max_width =
|
||||
MAX(self->page_content->count == 1 ? 0 : 100,
|
||||
UI_Label_MeasureTextWidth(self->title));
|
||||
int32_t max_nav_width = 0;
|
||||
int32_t max_height = 0;
|
||||
for (int32_t i = 0; i < self->page_content->count; i++) {
|
||||
M_SelectPage(self, i);
|
||||
max_width = MAX(max_width, UI_Label_MeasureTextWidth(self->text));
|
||||
max_height = MAX(max_height, UI_Label_MeasureTextHeight(self->text));
|
||||
if (self->bottom_stack != nullptr) {
|
||||
max_nav_width =
|
||||
MAX(max_nav_width, UI_Label_MeasureTextWidth(self->page_label));
|
||||
}
|
||||
}
|
||||
|
||||
UI_Label_SetSize(self->text, max_width, max_height);
|
||||
if (self->bottom_stack != nullptr) {
|
||||
UI_Stack_SetSize(self->bottom_stack, max_width, UI_STACK_AUTO_SIZE);
|
||||
UI_Label_SetSize(self->page_label, max_nav_width, UI_LABEL_AUTO_SIZE);
|
||||
}
|
||||
|
||||
M_SelectPage(self, 0);
|
||||
M_DoLayout(self);
|
||||
|
||||
return (UI_WIDGET *)self;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <libtrx/game/ui/widgets/base.h>
|
||||
|
||||
UI_WIDGET *UI_Paginator_Create(
|
||||
const char *title, const char *text, int32_t max_lines);
|
|
@ -264,7 +264,6 @@ sources = [
|
|||
'game/text.c',
|
||||
'game/ui/common.c',
|
||||
'game/ui/widgets/stats_dialog.c',
|
||||
'game/ui/widgets/paginator.c',
|
||||
'game/viewport.c',
|
||||
'global/enum_map.c',
|
||||
'global/vars.c',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue