Overhaul the VR menu UI: header, tabs, live video options, hover/click feedback, i18n, and dragging
build / build (push) Successful in 2m25s

- Header with title, git-tag-derived version, and a live FPS/frame-time/
  CPU/GPU-utilization/free-memory stats ribbon below the tab bar (FPS via
  a new per-frame tracker in xr_session.c; CPU/GPU via the OpenXR
  XR_META_performance_metrics extension, gracefully unavailable on
  runtimes that don't support it)
- Bottom tab bar with a live-editable Video Options tab (renderer/
  resolution), applying changes immediately via qs_config.c
- Hover and press feedback on every menu/keyboard button via a
  StateListDrawable (Android's default ripple never animates on this
  permanently unattached view tree), with a lighter default button color
  for visibility
- i18n for all menu/keyboard chrome text, following the game's own
  language setting (Strings.java)
- The main menu is now draggable via its header, matching the keyboard;
  xr_input.c's drag handling is generalized to per-overlay state instead
  of being keyboard-only
- The keyboard's title bar now matches the menu header's style
This commit is contained in:
ml
2026-09-05 07:02:30 +02:00
parent c4fd4eb3dd
commit 09280dd410
14 changed files with 1150 additions and 148 deletions
+52 -6
View File
@@ -442,6 +442,21 @@ static const char *qs_current_resolution(void) {
return "640x480"; // shouldn't happen - safe fallback for Save
}
// ===========================================================================
// Read-only queries for the Video Options tab (see qs_config.h)
// ===========================================================================
bool qs_config_current_renderer_is_opengl(void) { return gShockPrefs.doUseOpenGL; }
int qs_config_current_resolution_index(void) {
for (size_t i = 0; i < QS_NUM_RESOLUTIONS; i++)
if (kResolutions[i].mode == mode_id)
return (int)i;
return 3; // shouldn't happen - 640x480, matches qs_current_resolution()'s own fallback
}
int qs_config_current_language(void) { return gShockPrefs.goLanguage; }
// ===========================================================================
// Apply / Save orchestration
// ===========================================================================
@@ -557,16 +572,21 @@ static void qs_show_restart_dialog(const char *restart_needed) {
static Uint32 s_save_event_type;
static Uint32 s_load_event_type;
static Uint32 s_set_renderer_event_type;
static Uint32 s_set_resolution_event_type;
void qs_config_load_startup(void) {
// Registers the custom SDL event types qs_config_request_save()/_load()
// enqueue - done here, once, on the engine's own thread and before the
// menu/its buttons could possibly exist yet, rather than lazily from
// those functions themselves (which run on Android's UI thread and
// could otherwise race each other doing this lazily).
Uint32 base = SDL_RegisterEvents(2);
// Registers the custom SDL event types qs_config_request_save()/_load()/
// _set_renderer()/_set_resolution() enqueue - done here, once, on the
// engine's own thread and before the menu/its buttons could possibly
// exist yet, rather than lazily from those functions themselves (which
// run on Android's UI thread and could otherwise race each other doing
// this lazily).
Uint32 base = SDL_RegisterEvents(4);
s_save_event_type = base;
s_load_event_type = base + 1;
s_set_renderer_event_type = base + 2;
s_set_resolution_event_type = base + 3;
QsParsedConfig parsed;
if (qs_config_read_file(&parsed))
@@ -587,6 +607,22 @@ void qs_config_request_load(void) {
SDL_PushEvent(&event);
}
void qs_config_request_set_renderer(bool opengl) {
SDL_Event event;
SDL_zero(event);
event.type = s_set_renderer_event_type;
event.user.code = opengl ? 1 : 0;
SDL_PushEvent(&event);
}
void qs_config_request_set_resolution(int resolution_index) {
SDL_Event event;
SDL_zero(event);
event.type = s_set_resolution_event_type;
event.user.code = resolution_index;
SDL_PushEvent(&event);
}
bool qs_config_handle_event(const SDL_Event *event) {
if (event->type == s_save_event_type) {
if (qs_config_write_file())
@@ -609,5 +645,15 @@ bool qs_config_handle_event(const SDL_Event *event) {
message_info("Configuration loaded");
return true;
}
if (event->type == s_set_renderer_event_type) {
qs_apply_renderer(event->user.code ? "opengl" : "software", /*live=*/true);
return true;
}
if (event->type == s_set_resolution_event_type) {
int index = event->user.code;
if (index >= 0 && (size_t)index < QS_NUM_RESOLUTIONS)
qs_apply_resolution(kResolutions[index].name, /*live=*/true);
return true;
}
return false;
}