mirror of
https://github.com/LostArtefacts/TRX.git
synced 2025-04-28 12:47:58 +03:00
tr2/options: add graphic options dialog
Some checks are pending
Run code linters / Run code linters (push) Waiting to run
Some checks are pending
Run code linters / Run code linters (push) Waiting to run
Resolves #1615.
This commit is contained in:
parent
b8646e79ba
commit
3eabd3499e
14 changed files with 415 additions and 10 deletions
|
@ -364,9 +364,9 @@
|
|||
"DETAIL_RENDER_MODE_LEGACY": "Window size",
|
||||
"DETAIL_RESOLUTION": "Resolution",
|
||||
"DETAIL_RESOLUTION_FMT": "%dx%d",
|
||||
"DETAIL_SELECT_DETAIL": "Select Detail",
|
||||
"DETAIL_STRING_FMT": "%s",
|
||||
"DETAIL_TEXTURE_FILTER": "Texture filter",
|
||||
"DETAIL_TITLE": "Graphic Options",
|
||||
"DETAIL_TRAPEZOID_FILTER": "Trapezoid filter",
|
||||
"DETAIL_UI_BAR_SCALE": "UI bar scale",
|
||||
"DETAIL_UI_TEXT_SCALE": "UI text scale",
|
||||
|
|
|
@ -472,6 +472,10 @@
|
|||
"CONTROL_CUSTOM_3": "User Keys 3",
|
||||
"CONTROL_DEFAULT_KEYS": "Default Keys",
|
||||
"DETAIL_FLOAT_FMT": "%.1f",
|
||||
"DETAIL_FOG_END": "Fog end",
|
||||
"DETAIL_FOG_START": "Fog start",
|
||||
"DETAIL_INTEGER_FMT": "%d",
|
||||
"DETAIL_TITLE": "Graphic Options",
|
||||
"HEADING_GAME_OVER": "GAME OVER",
|
||||
"HEADING_INVENTORY": "INVENTORY",
|
||||
"HEADING_ITEMS": "ITEMS",
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
PS1 | 77 | 255 | 255 |  `#4DFFFF`
|
||||
DOS | 153 | 179 | 255 |  `#99B3FF`
|
||||
- changed the `draw_distance_min` and `draw_distance_max` to `fog_start` and `fog_end`
|
||||
- changed `Select Detail` dialog title to `Graphic Options`
|
||||
- fixed the bilinear filter to not readjust the UVs (#2258)
|
||||
- fixed anisotropy filter causing black lines on certain GPUs (#902)
|
||||
- fixed mesh faces not being drawn under some circumstances (#2452, #2438)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
## [Unreleased](https://github.com/LostArtefacts/TRX/compare/tr2-0.10...develop) - ××××-××-××
|
||||
- added support for The Golden Mask (#1621)
|
||||
- added sunglasses for graphic options (#1615)
|
||||
- added control over the fog distances for players and level builders (#1622)
|
||||
- added an installer for Windows (#2681)
|
||||
- added the bonus level game flow type, which allows for levels to be unlocked if all main game secrets are found (#2668)
|
||||
|
|
|
@ -163,6 +163,7 @@ as Notepad.
|
|||
- added support for more accented characters
|
||||
- added fade effects to displayed images
|
||||
- added a wireframe mode
|
||||
- added sunglasses for graphic options
|
||||
- improved support for windowed mode
|
||||
|
||||
#### Gameplay
|
||||
|
|
|
@ -127,4 +127,8 @@ GS_DEFINE(PASSPORT_EXIT_TO_TITLE, "Exit to Title")
|
|||
GS_DEFINE(SOUND_SET_VOLUMES, "Set Volumes")
|
||||
GS_DEFINE(OSD_TRAPEZOID_FILTER_ON, "Trapezoid filter enabled")
|
||||
GS_DEFINE(OSD_TRAPEZOID_FILTER_OFF, "Trapezoid filter disabled")
|
||||
GS_DEFINE(DETAIL_INTEGER_FMT, "%d")
|
||||
GS_DEFINE(DETAIL_FLOAT_FMT, "%.1f")
|
||||
GS_DEFINE(DETAIL_TITLE, "Graphic Options")
|
||||
GS_DEFINE(DETAIL_FOG_START, "Fog start")
|
||||
GS_DEFINE(DETAIL_FOG_END, "Fog end")
|
||||
|
|
|
@ -7,10 +7,7 @@ GS_DEFINE(PASSPORT_MODE_NEW_GAME, "New Game")
|
|||
GS_DEFINE(PASSPORT_MODE_NEW_GAME_PLUS, "New Game+")
|
||||
GS_DEFINE(PASSPORT_MODE_NEW_GAME_JP, "Japanese NG")
|
||||
GS_DEFINE(PASSPORT_MODE_NEW_GAME_JP_PLUS, "Japanese NG+")
|
||||
GS_DEFINE(DETAIL_SELECT_DETAIL, "Select Detail")
|
||||
GS_DEFINE(DETAIL_FPS, "FPS")
|
||||
GS_DEFINE(DETAIL_FOG_START, "Fog start")
|
||||
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)")
|
||||
|
@ -27,7 +24,6 @@ GS_DEFINE(DETAIL_RENDER_MODE, "Render mode")
|
|||
GS_DEFINE(DETAIL_RENDER_MODE_LEGACY, "Window size")
|
||||
GS_DEFINE(DETAIL_RENDER_MODE_FBO, "Framebuffer")
|
||||
GS_DEFINE(DETAIL_RESOLUTION, "Resolution")
|
||||
GS_DEFINE(DETAIL_INTEGER_FMT, "%d")
|
||||
GS_DEFINE(DETAIL_STRING_FMT, "%s")
|
||||
GS_DEFINE(DETAIL_RESOLUTION_FMT, "%dx%d")
|
||||
GS_DEFINE(CONTROL_RESET_DEFAULTS, "Reset All: Hold %s")
|
||||
|
|
|
@ -203,7 +203,7 @@ static void M_InitText(void)
|
|||
Text_CentreH(m_Text[TEXT_TITLE_BORDER], 1);
|
||||
Text_CentreV(m_Text[TEXT_TITLE_BORDER], 1);
|
||||
|
||||
m_Text[TEXT_TITLE] = Text_Create(0, TOP_Y, GS(DETAIL_SELECT_DETAIL));
|
||||
m_Text[TEXT_TITLE] = Text_Create(0, TOP_Y, GS(DETAIL_TITLE));
|
||||
Text_CentreH(m_Text[TEXT_TITLE], 1);
|
||||
Text_CentreV(m_Text[TEXT_TITLE], 1);
|
||||
Text_AddBackground(m_Text[TEXT_TITLE], ROW_WIDTH - 4, 0, 0, 0, TS_HEADING);
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#define TITLE_RING_OBJECTS 3
|
||||
#define OPTION_RING_OBJECTS 3
|
||||
#define TITLE_RING_OBJECTS 4
|
||||
#define OPTION_RING_OBJECTS 4
|
||||
#define INV_RING_FADE_TIME_FAST \
|
||||
(INV_RING_CLOSE_FRAMES / INV_RING_FRAMES / (double)LOGIC_FPS)
|
||||
#define INV_RING_FADE_TIME_TITLE_FINISH 0.25
|
||||
|
|
|
@ -44,11 +44,12 @@ INV_RING_SOURCE g_InvRing_Source[RT_NUMBER_OF] = {
|
|||
},
|
||||
},
|
||||
[RT_OPTION] = {
|
||||
.count = 4,
|
||||
.count = 5,
|
||||
.current = 0,
|
||||
.qtys = { 1, 1, 1, 1 },
|
||||
.qtys = { 1, 1, 1, 1, 1 },
|
||||
.items = {
|
||||
&g_InvRing_Item_Passport,
|
||||
&g_InvRing_Item_Graphics,
|
||||
&g_InvRing_Item_Controls,
|
||||
&g_InvRing_Item_Sound,
|
||||
&g_InvRing_Item_Photo,
|
||||
|
|
|
@ -1,16 +1,43 @@
|
|||
#include "game/input.h"
|
||||
#include "game/option/option.h"
|
||||
#include "game/text.h"
|
||||
#include "game/ui/widgets/graphics_dialog.h"
|
||||
#include "global/vars.h"
|
||||
|
||||
static struct {
|
||||
UI_WIDGET *widget;
|
||||
} m_Priv = {};
|
||||
|
||||
static void M_ConstructUI(void);
|
||||
static void M_DestroyUI(void);
|
||||
|
||||
static void M_ConstructUI(void)
|
||||
{
|
||||
m_Priv.widget = UI_GraphicsDialog_Create();
|
||||
}
|
||||
|
||||
static void M_DestroyUI(void)
|
||||
{
|
||||
if (m_Priv.widget != nullptr) {
|
||||
m_Priv.widget->free(m_Priv.widget);
|
||||
m_Priv.widget = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Option_Detail_Control(INVENTORY_ITEM *const item, const bool is_busy)
|
||||
{
|
||||
if (m_Priv.widget == nullptr) {
|
||||
M_ConstructUI();
|
||||
}
|
||||
m_Priv.widget->control(m_Priv.widget);
|
||||
}
|
||||
|
||||
void Option_Detail_Draw(INVENTORY_ITEM *const item)
|
||||
{
|
||||
m_Priv.widget->draw(m_Priv.widget);
|
||||
}
|
||||
|
||||
void Option_Detail_Shutdown(void)
|
||||
{
|
||||
M_DestroyUI();
|
||||
}
|
||||
|
|
364
src/tr2/game/ui/widgets/graphics_dialog.c
Normal file
364
src/tr2/game/ui/widgets/graphics_dialog.c
Normal file
|
@ -0,0 +1,364 @@
|
|||
#include "game/ui/widgets/graphics_dialog.h"
|
||||
|
||||
#include <libtrx/config.h>
|
||||
#include <libtrx/game/game_string.h>
|
||||
#include <libtrx/game/input.h>
|
||||
#include <libtrx/game/text.h>
|
||||
#include <libtrx/game/ui/common.h>
|
||||
#include <libtrx/game/ui/widgets/frame.h>
|
||||
#include <libtrx/game/ui/widgets/label.h>
|
||||
#include <libtrx/game/ui/widgets/stack.h>
|
||||
#include <libtrx/game/ui/widgets/window.h>
|
||||
#include <libtrx/log.h>
|
||||
#include <libtrx/memory.h>
|
||||
#include <libtrx/strings.h>
|
||||
|
||||
typedef struct {
|
||||
CONFIG_OPTION_TYPE option_type;
|
||||
GAME_STRING_ID label_id;
|
||||
void *target;
|
||||
int32_t min_value;
|
||||
int32_t max_value;
|
||||
} M_OPTION;
|
||||
|
||||
typedef struct {
|
||||
void *user_data;
|
||||
UI_WIDGET *frame;
|
||||
UI_WIDGET *stack;
|
||||
UI_WIDGET *title_label;
|
||||
UI_WIDGET *value_label;
|
||||
UI_WIDGET *arrow_left_label;
|
||||
UI_WIDGET *arrow_right_label;
|
||||
} M_ROW;
|
||||
|
||||
typedef struct {
|
||||
UI_WIDGET_VTABLE vtable;
|
||||
UI_WIDGET *window;
|
||||
UI_WIDGET *outer_stack;
|
||||
|
||||
int32_t visible_rows;
|
||||
|
||||
bool is_confirmed;
|
||||
int32_t selected_row_offset;
|
||||
int32_t visible_row_offset;
|
||||
int32_t row_count;
|
||||
M_ROW *rows;
|
||||
|
||||
int32_t selection_margin;
|
||||
int32_t selection_padding;
|
||||
|
||||
int32_t listener;
|
||||
} M_WIDGET;
|
||||
|
||||
static M_OPTION m_Options[] = {
|
||||
{
|
||||
.option_type = COT_INT32,
|
||||
.label_id = GS_ID(DETAIL_FOG_START),
|
||||
.target = &g_Config.visuals.fog_start,
|
||||
.min_value = 1,
|
||||
.max_value = 100,
|
||||
},
|
||||
{
|
||||
.option_type = COT_INT32,
|
||||
.label_id = GS_ID(DETAIL_FOG_END),
|
||||
.target = &g_Config.visuals.fog_end,
|
||||
.min_value = 1,
|
||||
.max_value = 100,
|
||||
},
|
||||
{
|
||||
.target = nullptr,
|
||||
},
|
||||
};
|
||||
|
||||
static void M_ClearRows(M_WIDGET *self);
|
||||
static char *M_FormatRowValue(int32_t row_idx);
|
||||
static bool M_CanChangeValue(int32_t row_idx, int32_t delta);
|
||||
static bool M_RequestChangeValue(
|
||||
M_WIDGET *self, int32_t row_idx, int32_t delta);
|
||||
static void M_DeselectRow(M_WIDGET *self, int32_t row_idx);
|
||||
static void M_SelectRow(M_WIDGET *self, int32_t row_idx);
|
||||
static M_ROW *M_AddRow(
|
||||
M_WIDGET *self, const char *left_text, const char *right_text,
|
||||
void *user_data);
|
||||
static void M_DoLayout(M_WIDGET *self);
|
||||
static void M_HandleCanvasResize(const EVENT *event, void *data);
|
||||
|
||||
static int32_t M_GetWidth(const M_WIDGET *self);
|
||||
static int32_t M_GetHeight(const M_WIDGET *self);
|
||||
static void M_SetPosition(M_WIDGET *self, int32_t x, int32_t y);
|
||||
static void M_Control(M_WIDGET *self);
|
||||
static void M_Draw(M_WIDGET *self);
|
||||
static void M_Free(M_WIDGET *self);
|
||||
|
||||
static void M_ClearRows(M_WIDGET *const self)
|
||||
{
|
||||
for (int32_t i = 0; i < self->row_count; i++) {
|
||||
self->rows[i].title_label->free(self->rows[i].title_label);
|
||||
self->rows[i].value_label->free(self->rows[i].value_label);
|
||||
self->rows[i].arrow_left_label->free(self->rows[i].arrow_left_label);
|
||||
self->rows[i].arrow_right_label->free(self->rows[i].arrow_right_label);
|
||||
self->rows[i].frame->free(self->rows[i].frame);
|
||||
self->rows[i].stack->free(self->rows[i].stack);
|
||||
}
|
||||
UI_Stack_ClearChildren(self->outer_stack);
|
||||
self->visible_row_offset = 0;
|
||||
self->row_count = 0;
|
||||
self->selected_row_offset = -1;
|
||||
self->is_confirmed = false;
|
||||
}
|
||||
|
||||
static char *M_FormatRowValue(const int32_t row_idx)
|
||||
{
|
||||
const M_OPTION *const option = &m_Options[row_idx];
|
||||
switch (option->option_type) {
|
||||
case COT_INT32:
|
||||
return String_Format(
|
||||
GS(DETAIL_INTEGER_FMT), *(int32_t *)option->target);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool M_CanChangeValue(const int32_t row_idx, const int32_t delta)
|
||||
{
|
||||
const M_OPTION *const option = &m_Options[row_idx];
|
||||
switch (option->option_type) {
|
||||
case COT_INT32:
|
||||
if (delta < 0) {
|
||||
return *(int32_t *)option->target > option->min_value;
|
||||
} else if (delta > 0) {
|
||||
return *(int32_t *)option->target < option->max_value;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool M_RequestChangeValue(
|
||||
M_WIDGET *const self, const int32_t row_idx, const int32_t delta)
|
||||
{
|
||||
if (!M_CanChangeValue(row_idx, delta)) {
|
||||
return false;
|
||||
}
|
||||
const M_OPTION *const option = &m_Options[row_idx];
|
||||
switch (option->option_type) {
|
||||
case COT_INT32:
|
||||
*(int32_t *)option->target += delta;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
M_ROW *const row = &self->rows[row_idx];
|
||||
char *value_text = M_FormatRowValue(row_idx);
|
||||
UI_Label_ChangeText(row->value_label, value_text);
|
||||
UI_Label_SetVisible(row->arrow_left_label, M_CanChangeValue(row_idx, -1));
|
||||
UI_Label_SetVisible(row->arrow_right_label, M_CanChangeValue(row_idx, +1));
|
||||
Memory_Free(value_text);
|
||||
Config_Write();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void M_DeselectRow(M_WIDGET *const self, const int32_t row_idx)
|
||||
{
|
||||
M_ROW *const row = &self->rows[row_idx];
|
||||
UI_Label_SetVisible(row->arrow_left_label, false);
|
||||
UI_Label_SetVisible(row->arrow_right_label, false);
|
||||
UI_Frame_SetFrameVisible(row->frame, false);
|
||||
}
|
||||
|
||||
static void M_SelectRow(M_WIDGET *const self, const int32_t row_idx)
|
||||
{
|
||||
M_ROW *const row = &self->rows[row_idx];
|
||||
UI_Label_SetVisible(row->arrow_left_label, M_CanChangeValue(row_idx, -1));
|
||||
UI_Label_SetVisible(row->arrow_right_label, M_CanChangeValue(row_idx, +1));
|
||||
UI_Frame_SetFrameVisible(row->frame, true);
|
||||
}
|
||||
|
||||
static M_ROW *M_AddRow(
|
||||
M_WIDGET *const self, const char *const left_text,
|
||||
const char *const right_text, void *const user_data)
|
||||
{
|
||||
self->row_count++;
|
||||
self->rows = Memory_Realloc(self->rows, sizeof(M_ROW) * self->row_count);
|
||||
M_ROW *const row = &self->rows[self->row_count - 1];
|
||||
|
||||
row->stack =
|
||||
UI_Stack_Create(UI_STACK_LAYOUT_HORIZONTAL, 200, UI_STACK_AUTO_SIZE);
|
||||
UI_Stack_SetHAlign(row->stack, UI_STACK_H_ALIGN_DISTRIBUTE);
|
||||
|
||||
row->frame = UI_Frame_Create(row->stack, 0, 0);
|
||||
UI_Frame_SetFrameVisible(row->frame, false);
|
||||
|
||||
row->title_label = UI_Label_Create(left_text, 120, UI_LABEL_AUTO_SIZE);
|
||||
UI_Stack_AddChild(row->stack, row->title_label);
|
||||
|
||||
row->arrow_left_label = UI_Label_Create(
|
||||
"\\{button left} ", UI_LABEL_AUTO_SIZE, UI_LABEL_AUTO_SIZE);
|
||||
UI_Label_SetVisible(row->arrow_left_label, false);
|
||||
UI_Stack_AddChild(row->stack, row->arrow_left_label);
|
||||
|
||||
row->value_label =
|
||||
UI_Label_Create(right_text, UI_LABEL_AUTO_SIZE, UI_LABEL_AUTO_SIZE);
|
||||
UI_Stack_AddChild(row->stack, row->value_label);
|
||||
|
||||
row->arrow_right_label = UI_Label_Create(
|
||||
" \\{button right}", UI_LABEL_AUTO_SIZE, UI_LABEL_AUTO_SIZE);
|
||||
UI_Label_SetVisible(row->arrow_right_label, false);
|
||||
UI_Stack_AddChild(row->stack, row->arrow_right_label);
|
||||
|
||||
row->user_data = user_data;
|
||||
|
||||
for (int32_t y = 0; y < self->row_count; y++) {
|
||||
self->rows[y].stack->is_hidden = y < self->visible_row_offset
|
||||
|| y >= self->visible_row_offset + self->visible_rows;
|
||||
}
|
||||
if (self->selected_row_offset == -1) {
|
||||
self->selected_row_offset = 0;
|
||||
M_SelectRow(self, self->selected_row_offset);
|
||||
}
|
||||
|
||||
UI_Stack_AddChild(self->outer_stack, row->frame);
|
||||
return row;
|
||||
}
|
||||
|
||||
static void M_DoLayout(M_WIDGET *const self)
|
||||
{
|
||||
M_SetPosition(
|
||||
self, (UI_GetCanvasWidth() - M_GetWidth(self)) / 2,
|
||||
(UI_GetCanvasHeight() - M_GetHeight(self)) * 3 / 5);
|
||||
}
|
||||
|
||||
static void M_HandleCanvasResize(const EVENT *event, void *data)
|
||||
{
|
||||
M_WIDGET *const self = (M_WIDGET *)data;
|
||||
M_DoLayout(self);
|
||||
}
|
||||
|
||||
static int32_t M_GetWidth(const M_WIDGET *const self)
|
||||
{
|
||||
return self->window->get_width(self->window);
|
||||
}
|
||||
|
||||
static int32_t M_GetHeight(const M_WIDGET *const self)
|
||||
{
|
||||
return self->window->get_height(self->window);
|
||||
}
|
||||
|
||||
static void M_SetPosition(
|
||||
M_WIDGET *const self, const int32_t x, const int32_t y)
|
||||
{
|
||||
self->window->set_position(self->window, x, y);
|
||||
}
|
||||
|
||||
static void M_Control(M_WIDGET *const self)
|
||||
{
|
||||
if (self->window->control != nullptr) {
|
||||
self->window->control(self->window);
|
||||
}
|
||||
|
||||
bool update = false;
|
||||
if (g_InputDB.menu_down) {
|
||||
if (self->visible_row_offset + self->visible_rows < self->row_count) {
|
||||
self->rows[self->visible_row_offset].stack->is_hidden = true;
|
||||
self->rows[self->visible_row_offset + self->visible_rows]
|
||||
.stack->is_hidden = false;
|
||||
self->visible_row_offset++;
|
||||
update = true;
|
||||
}
|
||||
} else if (g_InputDB.menu_up) {
|
||||
if (self->visible_row_offset > 0) {
|
||||
self->rows[self->visible_row_offset + self->visible_rows - 1]
|
||||
.stack->is_hidden = true;
|
||||
self->rows[self->visible_row_offset - 1].stack->is_hidden = false;
|
||||
self->visible_row_offset--;
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_down
|
||||
&& self->selected_row_offset + 1 < self->row_count) {
|
||||
if (self->selected_row_offset != -1) {
|
||||
M_DeselectRow(self, self->selected_row_offset);
|
||||
}
|
||||
self->selected_row_offset++;
|
||||
M_SelectRow(self, self->selected_row_offset);
|
||||
update = true;
|
||||
} else if (g_InputDB.menu_up && self->selected_row_offset > 0) {
|
||||
if (self->selected_row_offset != -1) {
|
||||
M_DeselectRow(self, self->selected_row_offset);
|
||||
}
|
||||
self->selected_row_offset--;
|
||||
M_SelectRow(self, self->selected_row_offset);
|
||||
update = true;
|
||||
}
|
||||
if (g_InputDB.menu_left && self->selected_row_offset >= 0) {
|
||||
M_RequestChangeValue(self, self->selected_row_offset, -1);
|
||||
} else if (g_InputDB.menu_right && self->selected_row_offset >= 0) {
|
||||
M_RequestChangeValue(self, self->selected_row_offset, +1);
|
||||
}
|
||||
|
||||
if (g_InputDB.menu_confirm) {
|
||||
self->is_confirmed = true;
|
||||
}
|
||||
|
||||
if (update) {
|
||||
M_DoLayout(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_Draw(M_WIDGET *const self)
|
||||
{
|
||||
if (self->window->draw != nullptr) {
|
||||
self->window->draw(self->window);
|
||||
}
|
||||
}
|
||||
|
||||
static void M_Free(M_WIDGET *const self)
|
||||
{
|
||||
M_ClearRows(self);
|
||||
self->outer_stack->free(self->outer_stack);
|
||||
self->window->free(self->window);
|
||||
UI_Events_Unsubscribe(self->listener);
|
||||
Memory_Free(self);
|
||||
}
|
||||
|
||||
UI_WIDGET *UI_GraphicsDialog_Create(void)
|
||||
{
|
||||
M_WIDGET *const self = Memory_Alloc(sizeof(M_WIDGET));
|
||||
|
||||
self->vtable = (UI_WIDGET_VTABLE) {
|
||||
.get_width = (UI_WIDGET_GET_WIDTH)M_GetWidth,
|
||||
.get_height = (UI_WIDGET_GET_HEIGHT)M_GetHeight,
|
||||
.set_position = (UI_WIDGET_SET_POSITION)M_SetPosition,
|
||||
.control = (UI_WIDGET_CONTROL)M_Control,
|
||||
.draw = (UI_WIDGET_DRAW)M_Draw,
|
||||
.free = (UI_WIDGET_FREE)M_Free,
|
||||
};
|
||||
|
||||
self->visible_rows = 2;
|
||||
self->outer_stack = UI_Stack_Create(
|
||||
UI_STACK_LAYOUT_VERTICAL, UI_STACK_AUTO_SIZE, UI_STACK_AUTO_SIZE);
|
||||
UI_Stack_SetHAlign(self->outer_stack, UI_STACK_H_ALIGN_CENTER);
|
||||
|
||||
self->window = UI_Window_Create(self->outer_stack, 8, 8, 8, 8);
|
||||
UI_Window_SetTitle(self->window, GS(DETAIL_TITLE));
|
||||
|
||||
self->selected_row_offset = -1;
|
||||
self->listener = UI_Events_Subscribe(
|
||||
"canvas_resize", nullptr, M_HandleCanvasResize, self);
|
||||
|
||||
for (int32_t i = 0; m_Options[i].target != nullptr; i++) {
|
||||
char *value_text = M_FormatRowValue(i);
|
||||
M_AddRow(
|
||||
self, GameString_Get(m_Options[i].label_id), value_text, nullptr);
|
||||
Memory_Free(value_text);
|
||||
}
|
||||
|
||||
M_DoLayout(self);
|
||||
return (UI_WIDGET *)self;
|
||||
}
|
5
src/tr2/game/ui/widgets/graphics_dialog.h
Normal file
5
src/tr2/game/ui/widgets/graphics_dialog.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <libtrx/game/ui/widgets/base.h>
|
||||
|
||||
UI_WIDGET *UI_GraphicsDialog_Create(void);
|
|
@ -283,6 +283,7 @@ sources = [
|
|||
'game/ui/widgets/controls_input_selector.c',
|
||||
'game/ui/widgets/controls_layout_editor.c',
|
||||
'game/ui/widgets/controls_layout_selector.c',
|
||||
'game/ui/widgets/graphics_dialog.c',
|
||||
'game/ui/widgets/stats_dialog.c',
|
||||
'game/viewport.c',
|
||||
'global/enum_map.c',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue