From 546936d04bf91dd877e7e6b7e2247e12fa5f0189 Mon Sep 17 00:00:00 2001 From: mcmartin Date: Wed, 5 Apr 2006 00:42:38 +0000 Subject: [PATCH] Content-driven Setup Menu Strings. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2301 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/ChangeLog | 1 + sc2/content/lbm/setupmenu.txt | 22 +- sc2/src/sc2code/libs/graphics/widgets.h | 25 - sc2/src/sc2code/libs/resource/alist.c | 7 +- sc2/src/sc2code/libs/resource/alist.h | 2 + sc2/src/sc2code/libs/resource/mapres.c | 2 +- sc2/src/sc2code/libs/resource/stringbank.c | 139 +++- sc2/src/sc2code/libs/resource/stringbank.h | 36 +- sc2/src/sc2code/setupmenu.c | 908 ++++++++++----------- 9 files changed, 604 insertions(+), 538 deletions(-) diff --git a/sc2/ChangeLog b/sc2/ChangeLog index 978949fd8..f0a8ae6cc 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,5 @@ Changes towards version 0.6: +- Setup menu reads strings out of lbm/setupmenu.txt - Michael - More fixes towards working 64-bits binaries. - Flashing outfit modules to build w/ PC menus too; bug #871 - Alex - Corrected caption Orbit: to Tilt: in planet scan; bug #847 - Alex diff --git a/sc2/content/lbm/setupmenu.txt b/sc2/content/lbm/setupmenu.txt index bf462d4e1..bcb568701 100644 --- a/sc2/content/lbm/setupmenu.txt +++ b/sc2/content/lbm/setupmenu.txt @@ -6,7 +6,7 @@ Ur-Quan Masters Setup Graphics Options Audio Options 3do/PC Options -Addon Packs +Resources Options Controls Setup Advanced Options @@ -185,11 +185,12 @@ PC #(CAT_9_OPT_0_DESC) Uses the music from the Original PC version. Prefers .MOD files to .OGG files. +Requires a restart of UQM to take effect. #(CAT_9_OPT_1_DESC) -Uses the music from the 3do version and/or the -Ur-Quan Masters Remix Project, if available. -Prefers .OGG files over .MOD. +Uses more modern music, if available. +Prefers .OGG files to .MOD files. +Requires a restart of UQM to take effect. #(CAT_10_OPTS) Windowed @@ -255,12 +256,18 @@ OpenAL #(CAT_15_OPT_0_DESC) Play silently. +This option will not take effect until +you restart UQM. #(CAT_15_OPT_1_DESC) Use the default audio mixer. +This option will not take effect until +you restart UQM. #(CAT_15_OPT_2_DESC) Use the Creative Labs OpenAL driver. +This option will not take effect until +you restart UQM. #(CAT_16_OPTS) Low @@ -269,13 +276,18 @@ High #(CAT_16_OPT_0_DESC) Low audio quality. +This option will not take effect until +you restart UQM. #(CAT_16_OPT_1_DESC) Medium audio quality. +This option will not take effect until +you restart UQM. #(CAT_16_OPT_2_DESC) Highest audio quality. -May not work on all architectures. +This option will not take effect until +you restart UQM. #(CAT_17_OPTS) Static diff --git a/sc2/src/sc2code/libs/graphics/widgets.h b/sc2/src/sc2code/libs/graphics/widgets.h index 7a84a56ca..171243a5f 100644 --- a/sc2/src/sc2code/libs/graphics/widgets.h +++ b/sc2/src/sc2code/libs/graphics/widgets.h @@ -142,29 +142,4 @@ void Widget_DrawSlider (WIDGET *_self, int x, int y); void Widget_Slider_DrawValue (WIDGET_SLIDER *self, int x, int y); -/* "Constructor" macros */ - -#define BUTTON_INIT(handler, name, ttip1, ttip2, ttip3) { \ - NULL, handler, Widget_ReceiveFocusSimple, Widget_DrawButton, \ - Widget_HeightOneLine, Widget_WidthFullScreen, \ - (name), { (ttip1), (ttip2), (ttip3) } } - -#define CHOICE_PREFACE NULL, Widget_HandleEventChoice, \ - Widget_ReceiveFocusChoice, Widget_DrawChoice, \ - Widget_HeightChoice, Widget_WidthFullScreen - -#define LABEL_PREFACE NULL, Widget_HandleEventIgnoreAll, \ - Widget_ReceiveFocusRefuseFocus, Widget_DrawLabel, \ - Widget_HeightLabel, Widget_WidthFullScreen - -#define MENU_SCREEN_PREFACE NULL, Widget_HandleEventMenuScreen, \ - Widget_ReceiveFocusMenuScreen, \ - Widget_DrawMenuScreen, Widget_HeightFullScreen, \ - Widget_WidthFullScreen - -#define SLIDER_PREFACE NULL, Widget_HandleEventSlider, \ - Widget_ReceiveFocusSimple, Widget_DrawSlider, \ - Widget_HeightOneLine, Widget_WidthFullScreen, \ - Widget_Slider_DrawValue - #endif /* _WIDGETS_H */ diff --git a/sc2/src/sc2code/libs/resource/alist.c b/sc2/src/sc2code/libs/resource/alist.c index 2360ae80f..41820d744 100644 --- a/sc2/src/sc2code/libs/resource/alist.c +++ b/sc2/src/sc2code/libs/resource/alist.c @@ -21,7 +21,6 @@ #include #include "libs/reslib.h" #include "alist.h" -#include "stringbank.h" alist_entry * AlistEntry_New (const char *key, const char *value) @@ -48,6 +47,7 @@ Alist_New (void) { alist *result = malloc (sizeof(alist)); result->first = NULL; + result->bank = StringBank_Create (); return result; } @@ -55,6 +55,7 @@ void Alist_Free (alist *m) { if (m == NULL) return; AlistEntry_Free (m->first); + StringBank_Free (m->bank); free (m); } @@ -198,8 +199,8 @@ Alist_New_FromString (char *d) make a new map entry. */ d[key_end] = '\0'; d[value_end] = '\0'; - Alist_PutString (m, StringBank_AddOrFindString(d+key_start), - StringBank_AddOrFindString(d+value_start)); + Alist_PutString (m, StringBank_AddOrFindString(m->bank, d+key_start), + StringBank_AddOrFindString(m->bank, d+value_start)); } return m; } diff --git a/sc2/src/sc2code/libs/resource/alist.h b/sc2/src/sc2code/libs/resource/alist.h index de1b110cb..9e3ee8758 100644 --- a/sc2/src/sc2code/libs/resource/alist.h +++ b/sc2/src/sc2code/libs/resource/alist.h @@ -20,6 +20,7 @@ #define _ALIST_H_ #include "libs/uio.h" +#include "stringbank.h" /* Associative List types. */ @@ -30,6 +31,7 @@ typedef struct _alist_entry { typedef struct _alist_map { alist_entry *first; + stringbank *bank; } alist; /* ***** alist_entry operations ***** */ diff --git a/sc2/src/sc2code/libs/resource/mapres.c b/sc2/src/sc2code/libs/resource/mapres.c index 49bd6943d..688dd7c29 100644 --- a/sc2/src/sc2code/libs/resource/mapres.c +++ b/sc2/src/sc2code/libs/resource/mapres.c @@ -53,7 +53,7 @@ static const char * int2str (int i) { char buf[20]; sprintf (buf, "%d", i); - return StringBank_AddOrFindString (buf); + return StringBank_AddOrFindString (map->bank, buf); } static int diff --git a/sc2/src/sc2code/libs/resource/stringbank.c b/sc2/src/sc2code/libs/resource/stringbank.c index 059c850d7..6015ca0de 100644 --- a/sc2/src/sc2code/libs/resource/stringbank.c +++ b/sc2/src/sc2code/libs/resource/stringbank.c @@ -22,55 +22,69 @@ #include "stringbank.h" -#define CHUNK_SIZE (1024 - sizeof (void *) - sizeof (int)) +typedef stringbank chunk; -typedef struct _stringbank_chunk { - char data[CHUNK_SIZE]; - int len; - struct _stringbank_chunk *next; -} chunk; - -static chunk *bank = NULL; - -static void -add_chunk (void) +static stringbank * +add_chunk (stringbank *bank) { - chunk *n = malloc (sizeof (chunk)); + stringbank *n = malloc (sizeof (stringbank)); n->len = 0; - n->next = bank; - bank = n; + n->next = NULL; + if (bank) + { + while (bank->next) + bank = bank->next; + bank->next = n; + } + return n; +} + +stringbank * +StringBank_Create (void) +{ + return add_chunk (NULL); +} + +void +StringBank_Free (stringbank *bank) +{ + if (bank) + { + StringBank_Free (bank->next); + free (bank); + } } const char * -StringBank_AddString (const char *str) +StringBank_AddString (stringbank *bank, const char *str) { - int len = strlen (str); - chunk *x = bank; - if (len > CHUNK_SIZE) + unsigned int len = strlen (str) + 1; + stringbank *x = bank; + if (len > STRBANK_CHUNK_SIZE) return NULL; while (x) { - int remaining = CHUNK_SIZE - x->len; + unsigned int remaining = STRBANK_CHUNK_SIZE - x->len; if (len < remaining) { char *result = x->data + x->len; strcpy (result, str); - x->len += len + 1; + x->len += len; return result; } x = x->next; } /* No room in any currently existing chunk */ - add_chunk (); - strcpy (bank->data, str); - bank->len += len + 1; - return bank->data; + x = add_chunk (bank); + strcpy (x->data, str); + x->len += len + 1; + return x->data; } const char * -StringBank_AddOrFindString (const char *str) +StringBank_AddOrFindString (stringbank *bank, const char *str) { - int len = strlen (str); - chunk *x = bank; - if (len > CHUNK_SIZE) + unsigned int len = strlen (str) + 1; + stringbank *x = bank; + if (len > STRBANK_CHUNK_SIZE) return NULL; while (x) { int i = 0; @@ -83,15 +97,76 @@ StringBank_AddOrFindString (const char *str) x = x->next; } /* We didn't find it, so add it */ - return StringBank_AddString (str); + return StringBank_AddString (bank, str); } -#ifdef DEBUG +static char buffer[STRBANK_CHUNK_SIZE]; + +const char * +StringBank_AddSubstring (stringbank *bank, const char *str, unsigned int n) +{ + unsigned int len = strlen (str); + if (n > len) + { + return StringBank_AddString (bank, str); + } + if (n >= STRBANK_CHUNK_SIZE) + { + return NULL; + } + strncpy (buffer, str, n); + buffer[n] = '\0'; + return StringBank_AddString(bank, buffer); +} + +const char * +StringBank_AddOrFindSubstring (stringbank *bank, const char *str, unsigned int n) +{ + unsigned int len = strlen (str); + if (n > len) + { + return StringBank_AddOrFindString (bank, str); + } + if (n >= STRBANK_CHUNK_SIZE) + { + return NULL; + } + strncpy (buffer, str, n); + buffer[n] = '\0'; + return StringBank_AddOrFindString(bank, buffer); +} + +int +SplitString (const char *s, char splitchar, int n, const char **result, stringbank *bank) +{ + int i; + const char *index = s; + + for (i = 0; i < n-1; i++) + { + const char *next; + int len; + + next = strchr (index, splitchar); + if (!next) + { + break; + } + + len = next - index; + result[i] = StringBank_AddOrFindSubstring (bank, index, len); + index = next+1; + } + result[i] = StringBank_AddOrFindString (bank, index); + return i+1; +} + +#ifdef SB_DEBUG void -StringBank_Dump (FILE *s) +StringBank_Dump (stringbank *bank, FILE *s) { - chunk *x = bank; + stringbank *x = bank; while (x) { int i = 0; while (i < x->len) { diff --git a/sc2/src/sc2code/libs/resource/stringbank.h b/sc2/src/sc2code/libs/resource/stringbank.h index 94e0aa807..c60a86724 100644 --- a/sc2/src/sc2code/libs/resource/stringbank.h +++ b/sc2/src/sc2code/libs/resource/stringbank.h @@ -19,19 +19,39 @@ #ifndef _STRINGBANK_H_ #define _STRINGBANK_H_ -#ifdef DEBUG +#ifdef SB_DEBUG #include #endif -/* Put str into the string bank. */ -const char *StringBank_AddString (const char *str); +#define STRBANK_CHUNK_SIZE (1024 - sizeof (void *) - sizeof (int)) -/* Put str into the string bank if it's not already there. Much slower. */ -const char *StringBank_AddOrFindString (const char *str); +typedef struct _stringbank_chunk { + char data[STRBANK_CHUNK_SIZE]; + int len; + struct _stringbank_chunk *next; +} stringbank; -#ifdef DEBUG +/* Constructors and destructors */ +stringbank *StringBank_Create (void); +void StringBank_Free (stringbank *bank); + +/* Put str or n chars after str into the string bank. */ +const char *StringBank_AddString (stringbank *bank, const char *str); +const char *StringBank_AddSubstring (stringbank *bank, const char *str, unsigned int n); + +/* Put str or n chars after str into the string bank if it's not already + there. Much slower. */ +const char *StringBank_AddOrFindString (stringbank *bank, const char *str); +const char *StringBank_AddOrFindSubstring (stringbank *bank, const char *str, unsigned int n); + +/* Split a string s into at most n substrings, separated by splitchar. + Pointers to these substrings will be stored in result; the + substrings themselves will be filed in the specified stringbank. */ +int SplitString (const char *s, char splitchar, int n, const char **result, stringbank *bank); + +#ifdef SB_DEBUG /* Print out a list of the contents of the string bank to the named stream. */ -void StringBank_Dump (FILE *s); -#endif /* DEBUG */ +void StringBank_Dump (stringbank *bank, FILE *s); +#endif /* SB_DEBUG */ #endif /* _STRINGBANK_H_ */ diff --git a/sc2/src/sc2code/setupmenu.c b/sc2/src/sc2code/setupmenu.c index 99c07b635..f1c992927 100644 --- a/sc2/src/sc2code/setupmenu.c +++ b/sc2/src/sc2code/setupmenu.c @@ -29,6 +29,7 @@ #include "libs/strlib.h" #include "libs/reslib.h" #include "libs/sound/sound.h" +#include "libs/resource/stringbank.h" #include "resinst.h" #include "nameref.h" @@ -57,417 +58,100 @@ static int do_resources (WIDGET *self, int event); static int do_keyconfig (WIDGET *self, int event); static int do_advanced (WIDGET *self, int event); -static CHOICE_OPTION scaler_opts[] = { - { "None", - { "No scaling.", - "Simulates the original 320x240 display.", - "Fastest, though least attractive, option.", - } }, - { "Bilinear", - { "Bilinear average scaling.", - "A simple, fast blending technique.", - "Hardware-accelerated in OpenGL mode." - } }, - { "Biadapt", - { "Adaptive bilinear scaling.", - "A slower, less blurry blending technique.", - "" - } }, - { "Biadv", - { "Advanced bilinear scaling.", - "Hand-weighted blend that produces smoother curves.", - "The most expensive scaler." - } }, - { "Triscan", - { "An interpolating scaler.", - "Produces sharp edges, but at a higher resolution.", - "Based on the Scale2x algorithm.", - } }, - { "HQ", - { "A high quality, very expensive interpolating scaler.", - "Produces sharp edges, but at a higher resolution.", - "Based on the HQ2X algorithm.", } } }; - -static CHOICE_OPTION scanlines_opts[] = { - { "Disabled", - { "Do not attempt to simulate an interlaced display.", - "", - "" - } }, - { "Enabled", - { "Simulate an interlaced display.", - "", - "" - } } }; - -static CHOICE_OPTION music_opts[] = { - { "PC", - { "Uses the music from the Original PC version.", - "Prefers .MOD files to .OGG files.", - "" - } }, - { "3do/Remixes", - { "Uses the music from the 3do version and/or the", - "Ur-Quan Masters Remix Project, if available.", - "Prefers .OGG files over .MOD." - } } }; - -static CHOICE_OPTION meleezoom_opts[] = { - { "Stepped", - { "Cut between three zoom levels in combat.", - "Resembles PC combat.", - "" } }, - { "Smooth", - { "Continuously scale the combat view.", - "Resembles 3do combat.", - "" } } }; - -static CHOICE_OPTION stereo_opts[] = { - { "Disabled", { "Sound effects are center-channel.", "", "" } }, - { "Enabled", - { "Uses positional SFX if possible..", - "Currently only supported on OpenAL.", "" } } }; - -static CHOICE_OPTION fps_opts[] = { - { "No", { "Do not show FPS in the console window.", "", "" } } , - { "Yes", { "Show FPS in the console window.", "", "" } } }; - -static CHOICE_OPTION intro_opts[] = { - { "Slides", - { "Prefer slides to movies if both are present.", - "Forces the PC intro.", - "" } }, - { "Movie", - { "Prefer movies to slides.", - "Will use 3do content if present.", - "", } } }; - -static CHOICE_OPTION menu_opts[] = { - { "Text", - { "In-game menus resemble the Original PC version.", - "", - "" - } }, - { "Pictographic", - { "In-game menus resemble the 3do version.", - "", - "" - } } }; - -static CHOICE_OPTION font_opts[] = { - { "Gradients", - { "Certain menu texts and dialogs use gradients,", - "as per the original PC version.", - "Looks nicer." - } }, - { "Flat", - { "All text and menus use a \"flat\" colour scheme,", - "as per the 3do version.", - "Easier to read." - } } }; - -static CHOICE_OPTION scan_opts[] = { - { "Text", - { "Displays planet scan information as text,", - "as per the original PC version.", - "" - } }, - { "Pictograms", - { "Displays planet scan information as pictograms,", - "as per the 3do version..", - "" - } } }; - -static CHOICE_OPTION scroll_opts[] = { - { "Per-Page", - { "When fast-forwarding or rewinding conversations", - "in-game, advance one screen of subtitles at a time.", - "This mimics the original PC version." - } }, - { "Smooth", - { "When fast-forwarding or rewinding conversations", - "in-game, advance at a linear rate.", - "This mimics the 3do version." - } } }; - -static CHOICE_OPTION subtitles_opts[] = { - { "Disabled", - { "Do not subtitle alien speech.", - "", - "" - } }, - { "Enabled", - { "Show subtitles for alien speech.", - "", - "" - } } }; - -static CHOICE_OPTION shield_opts[] = { - { "Static", - { "Slave shields maintain a static glow.", - "This mimics the PC version.", - "" - } }, - { "Pulsating", - { "Slave shields pulsate.", - "This mimics the 3do verion.", - "" - } } }; - -static CHOICE_OPTION res_opts[] = { - { "320x240", - { "320x240 resolution.", - "Available with SDL framebuffer or OpenGL.", - "" - } }, - { "640x480", - { "640x480 resolution.", - "Available with SDL framebuffer or OpenGL.", - "" - } }, -#ifdef HAVE_OPENGL - { "800x600", - { "800x600 resolution.", - "Requires OpenGL graphics drivers.", - "" - } }, - { "1024x768", - { "1024x768 resolution.", - "Requires OpenGL graphics drivers.", - "" - } }, - { "Custom", - { "Custom resolution set from the commandline.", - "Requires OpenGL graphics drivers.", - "" - } }, -#endif -}; - -static CHOICE_OPTION driver_opts[] = { - { "If Possible", - { "Uses SDL Framebuffer mode if possible,", - "and OpenGL otherwise. Framebuffer mode", - "is available for 320x240 and 640x480." - } }, - { "Never", - { "Always use OpenGL.", - "OpenGL can produce any resolution and is", - "usually hardware-accelerated." - } }, -}; - -static CHOICE_OPTION fullscreen_opts[] = { - { "Windowed", - { "Display everything in a window.", - "(if windowing is available)", - "" - } }, - { "Fullscreen", - { "Game occupies the entire screen.", - "(if available)", - "" - } }, -}; - -static CHOICE_OPTION aquality_opts[] = { - { "Low", - { "Low audio quality.", "", "" } }, - { "Medium", - { "Medium audio quality.", "", "" } }, - { "High", - { "Highest audio quality.", - "May not work on all architectures.", "" } } -}; - -static CHOICE_OPTION adriver_opts[] = { - { "None", - { "Play silently.", "", "" } }, - { "MixSDL", - { "Use the default audio mixer.", "", "" } }, - { "OpenAL", - { "Use the Creative Labs OpenAL driver.", "", "" } } }; - #ifdef HAVE_OPENGL #define RES_OPTS 4 #else #define RES_OPTS 2 #endif -static WIDGET_CHOICE cmdline_opts[] = { - { CHOICE_PREFACE, "Resolution", RES_OPTS, 3, res_opts, 0, 0}, - { CHOICE_PREFACE, "Use Framebuffer?", 2, 2, driver_opts, 0, 0}, - { CHOICE_PREFACE, "Scaler", 6, 3, scaler_opts, 0, 0 }, - { CHOICE_PREFACE, "Scanlines", 2, 3, scanlines_opts, 0, 0 }, - { CHOICE_PREFACE, "Menu Style", 2, 2, menu_opts, 0, 0 }, - { CHOICE_PREFACE, "Font Style", 2, 2, font_opts, 0, 0 }, - { CHOICE_PREFACE, "Scan Style", 2, 2, scan_opts, 0, 0 }, - { CHOICE_PREFACE, "Scroll Style", 2, 2, scroll_opts, 0, 0 }, - { CHOICE_PREFACE, "Subtitles", 2, 2, subtitles_opts, 0, 0 }, - { CHOICE_PREFACE, "Music Format", 2, 2, music_opts, 0, 0 }, - { CHOICE_PREFACE, "Display", 2, 2, fullscreen_opts, 0, 0}, - { CHOICE_PREFACE, "Cutscenes", 2, 2, intro_opts, 0, 0 }, - { CHOICE_PREFACE, "Show FPS", 2, 3, fps_opts, 0, 0 }, - { CHOICE_PREFACE, "Melee Zoom", 2, 2, meleezoom_opts, 0, 0 }, - { CHOICE_PREFACE, "Positional Audio", 2, 2, stereo_opts, 0, 0 }, - { CHOICE_PREFACE, "Sound Driver", 3, 3, adriver_opts, 0, 0 }, - { CHOICE_PREFACE, "Sound Quality", 3, 3, aquality_opts, 0, 0 }, - { CHOICE_PREFACE, "Slave Shields", 2, 2, shield_opts, 0, 0 } }; +#define MENU_COUNT 7 +#define CHOICE_COUNT 18 +#define SLIDER_COUNT 3 +#define BUTTON_COUNT 8 +#define LABEL_COUNT 1 -static WIDGET_SLIDER sliders_opts[] = { - { SLIDER_PREFACE, 0, 100, 5, 75, "Music Volume", { "Sets the music volume.", "", "" } }, - { SLIDER_PREFACE, 0, 100, 5, 75, "SFX Volume", { "Sets the sound effects volume.", "", "" } }, - { SLIDER_PREFACE, 0, 100, 5, 75, "Speech Volume", { "Sets the speech volume.", "", "" } }, -}; +/* The space for our widgets */ +static WIDGET_MENU_SCREEN menus[MENU_COUNT]; +static WIDGET_CHOICE choices[CHOICE_COUNT]; +static WIDGET_SLIDER sliders[SLIDER_COUNT]; +static WIDGET_BUTTON buttons[BUTTON_COUNT]; +static WIDGET_LABEL labels[LABEL_COUNT]; -static WIDGET_BUTTON quit_button = BUTTON_INIT (quit_main_menu, - "Quit Setup Menu", - "Return to the main menu.", "", ""); +/* The hardcoded data that isn't strings */ -static WIDGET_BUTTON prev_button = BUTTON_INIT (quit_sub_menu, - "Return to Main Menu", - "Save changes and return to main menu.", - "Changes will not be applied until", - "you quit setup entirely."); +typedef int (*HANDLER)(WIDGET *, int); -static WIDGET_BUTTON graphics_button = BUTTON_INIT (do_graphics, "Graphics Options", - "Configure display options for UQM.", - "Graphics drivers, resolution, and scalers.", ""); +static int choice_widths[CHOICE_COUNT] = { + 3, 2, 3, 3, 2, 2, 2, 2, 2, + 2, 2, 2, 3, 2, 2, 3, 3, 2 }; -static WIDGET_BUTTON engine_button = BUTTON_INIT (do_engine, "PC/3do Compatibility Options", - "Configure behavior of UQM", - "to more closely match the PC or 3do behavior.", ""); +static HANDLER button_handlers[BUTTON_COUNT] = { + quit_main_menu, quit_sub_menu, do_graphics, do_engine, + do_audio, do_resources, do_keyconfig, do_advanced }; -static WIDGET_BUTTON audio_button = BUTTON_INIT (do_audio, "Sound Options", - "Configure sound and audio options for UQM.", "", ""); +static int menu_sizes[MENU_COUNT] = { + 7, 5, 6, 9, 2, 2, +#ifdef HAVE_OPENGL + 5 }; +#else + 4 }; +#endif -static WIDGET_BUTTON resources_button = BUTTON_INIT (do_resources, "Resources Options", - "Configure UQM Addon Packs.", "", "Currently unimplemented."); - -static WIDGET_BUTTON keyconfig_button = BUTTON_INIT (do_keyconfig, "Configure Controls", - "Set up keyboard and joystick controls.", "", "Currently unimplemented."); - -static WIDGET_BUTTON advanced_button = BUTTON_INIT (do_advanced, "Advanced Options", - "Select underlying drivers or other", "hardware-dependent options.", ""); - -static const char *incomplete_msg[] = { - "This part of the configuration", - "has not yet been implemented.", - "", - "Expect it in a future version." }; - -static WIDGET_LABEL incomplete_label = { - LABEL_PREFACE, - 4, incomplete_msg }; +static int menu_bgs[MENU_COUNT] = { 0, 1, 1, 2, 3, 1, 2 }; +/* These refer to uninitialized widgets, but that's OK; we'll fill + * them in before we touch them */ static WIDGET *main_widgets[] = { - (WIDGET *)(&graphics_button), - (WIDGET *)(&audio_button), - (WIDGET *)(&engine_button), - (WIDGET *)(&resources_button), - (WIDGET *)(&keyconfig_button), - (WIDGET *)(&advanced_button), - (WIDGET *)(&quit_button) }; + (WIDGET *)(&buttons[2]), + (WIDGET *)(&buttons[3]), + (WIDGET *)(&buttons[4]), + (WIDGET *)(&buttons[5]), + (WIDGET *)(&buttons[6]), + (WIDGET *)(&buttons[7]), + (WIDGET *)(&buttons[0]) }; static WIDGET *graphics_widgets[] = { - (WIDGET *)(&cmdline_opts[0]), - (WIDGET *)(&cmdline_opts[10]), - (WIDGET *)(&cmdline_opts[2]), - (WIDGET *)(&cmdline_opts[3]), - (WIDGET *)(&prev_button) }; + (WIDGET *)(&choices[0]), + (WIDGET *)(&choices[10]), + (WIDGET *)(&choices[2]), + (WIDGET *)(&choices[3]), + (WIDGET *)(&buttons[1]) }; static WIDGET *audio_widgets[] = { - (WIDGET *)(&sliders_opts[0]), - (WIDGET *)(&sliders_opts[1]), - (WIDGET *)(&sliders_opts[2]), - (WIDGET *)(&cmdline_opts[14]), - (WIDGET *)(&cmdline_opts[9]), - (WIDGET *)(&prev_button) }; + (WIDGET *)(&sliders[0]), + (WIDGET *)(&sliders[1]), + (WIDGET *)(&sliders[2]), + (WIDGET *)(&choices[14]), + (WIDGET *)(&choices[9]), + (WIDGET *)(&buttons[1]) }; static WIDGET *engine_widgets[] = { - (WIDGET *)(&cmdline_opts[4]), - (WIDGET *)(&cmdline_opts[5]), - (WIDGET *)(&cmdline_opts[6]), - (WIDGET *)(&cmdline_opts[7]), - (WIDGET *)(&cmdline_opts[8]), - (WIDGET *)(&cmdline_opts[13]), - (WIDGET *)(&cmdline_opts[11]), - (WIDGET *)(&cmdline_opts[17]), - (WIDGET *)(&prev_button) }; + (WIDGET *)(&choices[4]), + (WIDGET *)(&choices[5]), + (WIDGET *)(&choices[6]), + (WIDGET *)(&choices[7]), + (WIDGET *)(&choices[8]), + (WIDGET *)(&choices[13]), + (WIDGET *)(&choices[11]), + (WIDGET *)(&choices[17]), + (WIDGET *)(&buttons[1]) }; static WIDGET *advanced_widgets[] = { #ifdef HAVE_OPENGL - (WIDGET *)(&cmdline_opts[1]), + (WIDGET *)(&choices[1]), #endif - (WIDGET *)(&cmdline_opts[12]), - (WIDGET *)(&cmdline_opts[15]), - (WIDGET *)(&cmdline_opts[16]), - (WIDGET *)(&prev_button) }; + (WIDGET *)(&choices[12]), + (WIDGET *)(&choices[15]), + (WIDGET *)(&choices[16]), + (WIDGET *)(&buttons[1]) }; - static WIDGET *incomplete_widgets[] = { - (WIDGET *)(&incomplete_label), - (WIDGET *)(&prev_button) }; - -static WIDGET_MENU_SCREEN menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "", - { {0, 0}, NULL }, - 7, main_widgets, - 0 }; + (WIDGET *)(&labels[0]), + (WIDGET *)(&buttons[1]) }; -static WIDGET_MENU_SCREEN graphics_menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "Graphics Options", - { {0, 0}, NULL }, - 5, graphics_widgets, - 0 }; - -static WIDGET_MENU_SCREEN audio_menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "Audio Options", - { {0, 0}, NULL }, - 6, audio_widgets, - 0 }; - -static WIDGET_MENU_SCREEN engine_menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "3do/PC Options", - { {0, 0}, NULL }, - 9, engine_widgets, - 0 }; - -static WIDGET_MENU_SCREEN resources_menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "Addon Packs", - { {0, 0}, NULL }, - 2, incomplete_widgets, - 0 }; - -static WIDGET_MENU_SCREEN keyconfig_menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "Controls Setup", - { {0, 0}, NULL }, - 2, incomplete_widgets, - 0 }; - -static WIDGET_MENU_SCREEN advanced_menu = { - MENU_SCREEN_PREFACE, - "Ur-Quan Masters Setup", - "Advanced Options", - { {0, 0}, NULL }, -#ifdef HAVE_OPENGL - 5, advanced_widgets, -#else - 4, advanced_widgets, -#endif - 0 }; +static WIDGET **menu_widgets[MENU_COUNT] = { + main_widgets, graphics_widgets, audio_widgets, engine_widgets, + incomplete_widgets, incomplete_widgets, advanced_widgets }; static int quit_main_menu (WIDGET *self, int event) @@ -486,7 +170,7 @@ quit_sub_menu (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&menu); + next = (WIDGET *)(&menus[0]); (*next->receiveFocus) (next, WIDGET_EVENT_SELECT); return TRUE; } @@ -499,7 +183,7 @@ do_graphics (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&graphics_menu); + next = (WIDGET *)(&menus[1]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); return TRUE; } @@ -512,7 +196,7 @@ do_audio (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&audio_menu); + next = (WIDGET *)(&menus[2]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); return TRUE; } @@ -525,7 +209,7 @@ do_engine (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&engine_menu); + next = (WIDGET *)(&menus[3]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); return TRUE; } @@ -538,7 +222,7 @@ do_resources (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&resources_menu); + next = (WIDGET *)(&menus[4]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); return TRUE; } @@ -551,7 +235,7 @@ do_keyconfig (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&keyconfig_menu); + next = (WIDGET *)(&menus[5]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); return TRUE; } @@ -564,7 +248,7 @@ do_advanced (WIDGET *self, int event) { if (event == WIDGET_EVENT_SELECT) { - next = (WIDGET *)(&advanced_menu); + next = (WIDGET *)(&menus[6]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); return TRUE; } @@ -585,62 +269,62 @@ SetDefaults (void) GetGlobalOptions (&opts); if (opts.res == OPTVAL_CUSTOM) { - cmdline_opts[0].numopts = RES_OPTS + 1; + choices[0].numopts = RES_OPTS + 1; } else { - cmdline_opts[0].numopts = RES_OPTS; + choices[0].numopts = RES_OPTS; } - cmdline_opts[0].selected = opts.res; - cmdline_opts[1].selected = opts.driver; - cmdline_opts[2].selected = opts.scaler; - cmdline_opts[3].selected = opts.scanlines; - cmdline_opts[4].selected = opts.menu; - cmdline_opts[5].selected = opts.text; - cmdline_opts[6].selected = opts.cscan; - cmdline_opts[7].selected = opts.scroll; - cmdline_opts[8].selected = opts.subtitles; - cmdline_opts[9].selected = opts.music; - cmdline_opts[10].selected = opts.fullscreen; - cmdline_opts[11].selected = opts.intro; - cmdline_opts[12].selected = opts.fps; - cmdline_opts[13].selected = opts.meleezoom; - cmdline_opts[14].selected = opts.stereo; - cmdline_opts[15].selected = opts.adriver; - cmdline_opts[16].selected = opts.aquality; - cmdline_opts[17].selected = opts.shield; + choices[0].selected = opts.res; + choices[1].selected = opts.driver; + choices[2].selected = opts.scaler; + choices[3].selected = opts.scanlines; + choices[4].selected = opts.menu; + choices[5].selected = opts.text; + choices[6].selected = opts.cscan; + choices[7].selected = opts.scroll; + choices[8].selected = opts.subtitles; + choices[9].selected = opts.music; + choices[10].selected = opts.fullscreen; + choices[11].selected = opts.intro; + choices[12].selected = opts.fps; + choices[13].selected = opts.meleezoom; + choices[14].selected = opts.stereo; + choices[15].selected = opts.adriver; + choices[16].selected = opts.aquality; + choices[17].selected = opts.shield; - sliders_opts[0].value = opts.musicvol; - sliders_opts[1].value = opts.sfxvol; - sliders_opts[2].value = opts.speechvol; + sliders[0].value = opts.musicvol; + sliders[1].value = opts.sfxvol; + sliders[2].value = opts.speechvol; } static void PropagateResults (void) { GLOBALOPTS opts; - opts.res = cmdline_opts[0].selected; - opts.driver = cmdline_opts[1].selected; - opts.scaler = cmdline_opts[2].selected; - opts.scanlines = cmdline_opts[3].selected; - opts.menu = cmdline_opts[4].selected; - opts.text = cmdline_opts[5].selected; - opts.cscan = cmdline_opts[6].selected; - opts.scroll = cmdline_opts[7].selected; - opts.subtitles = cmdline_opts[8].selected; - opts.music = cmdline_opts[9].selected; - opts.fullscreen = cmdline_opts[10].selected; - opts.intro = cmdline_opts[11].selected; - opts.fps = cmdline_opts[12].selected; - opts.meleezoom = cmdline_opts[13].selected; - opts.stereo = cmdline_opts[14].selected; - opts.adriver = cmdline_opts[15].selected; - opts.aquality = cmdline_opts[16].selected; - opts.shield = cmdline_opts[17].selected; + opts.res = choices[0].selected; + opts.driver = choices[1].selected; + opts.scaler = choices[2].selected; + opts.scanlines = choices[3].selected; + opts.menu = choices[4].selected; + opts.text = choices[5].selected; + opts.cscan = choices[6].selected; + opts.scroll = choices[7].selected; + opts.subtitles = choices[8].selected; + opts.music = choices[9].selected; + opts.fullscreen = choices[10].selected; + opts.intro = choices[11].selected; + opts.fps = choices[12].selected; + opts.meleezoom = choices[13].selected; + opts.stereo = choices[14].selected; + opts.adriver = choices[15].selected; + opts.aquality = choices[16].selected; + opts.shield = choices[17].selected; - opts.musicvol = sliders_opts[0].value; - opts.sfxvol = sliders_opts[1].value; - opts.speechvol = sliders_opts[2].value; + opts.musicvol = sliders[0].value; + opts.sfxvol = sliders[1].value; + opts.speechvol = sliders[2].value; SetGlobalOptions (&opts); } @@ -654,36 +338,11 @@ DoSetupMenu (PSETUP_MENU_STATE pInputState) SetDefaults (); current = NULL; - next = (WIDGET *)(&menu); + next = (WIDGET *)(&menus[0]); (*next->receiveFocus) (next, WIDGET_EVENT_DOWN); pInputState->initialized = TRUE; } - if (!menu.bgStamp.frame) - { - FRAME f = CaptureDrawable (LoadGraphic (MENUBKG_PMAP_ANIM)); - menu.bgStamp.origin.x = 0; - menu.bgStamp.origin.y = 0; - menu.bgStamp.frame = SetAbsFrameIndex (f, 0); - graphics_menu.bgStamp.origin.x = 0; - graphics_menu.bgStamp.origin.y = 0; - graphics_menu.bgStamp.frame = SetAbsFrameIndex (f, 1); - audio_menu.bgStamp.origin.x = 0; - audio_menu.bgStamp.origin.y = 0; - audio_menu.bgStamp.frame = SetAbsFrameIndex (f, 1); - engine_menu.bgStamp.origin.x = 0; - engine_menu.bgStamp.origin.y = 0; - engine_menu.bgStamp.frame = SetAbsFrameIndex (f, 2); - resources_menu.bgStamp.origin.x = 0; - resources_menu.bgStamp.origin.y = 0; - resources_menu.bgStamp.frame = SetAbsFrameIndex (f, 3); - keyconfig_menu.bgStamp.origin.x = 0; - keyconfig_menu.bgStamp.origin.y = 0; - keyconfig_menu.bgStamp.frame = SetAbsFrameIndex (f, 1); - advanced_menu.bgStamp.origin.x = 0; - advanced_menu.bgStamp.origin.y = 0; - advanced_menu.bgStamp.frame = SetAbsFrameIndex (f, 2); - } if (current != next) { SetTransitionSource (NULL); @@ -731,6 +390,327 @@ DoSetupMenu (PSETUP_MENU_STATE pInputState) (next == NULL)); } +static stringbank *bank = NULL; +static FRAME setup_frame = NULL; + + +static void +init_widgets (void) +{ + const char *buffer[100], *str, *title; + int count, i, index; + + if (bank == NULL) + { + bank = StringBank_Create (); + } + + if (setup_frame == NULL) + { + setup_frame = CaptureDrawable (LoadGraphic (MENUBKG_PMAP_ANIM)); + } + + count = GetStringTableCount (SetupTab); + + if (count < 3) + { + fprintf (stderr, "PANIC: Setup string table too short to even hold all indices!\n"); + exit (1); + } + + /* Menus */ + title = StringBank_AddOrFindString (bank, GetStringAddress (SetAbsStringTableIndex (SetupTab, 0))); + if (SplitString (GetStringAddress (SetAbsStringTableIndex (SetupTab, 1)), '\n', 100, buffer, bank) != MENU_COUNT) + { + /* TODO: Ignore extras instead of dying. */ + fprintf (stderr, "PANIC: Incorrect number of Menu Subtitles\n"); + exit (1); + } + + for (i = 0; i < MENU_COUNT; i++) + { + menus[i].parent = NULL; + menus[i].handleEvent = Widget_HandleEventMenuScreen; + menus[i].receiveFocus = Widget_ReceiveFocusMenuScreen; + menus[i].draw = Widget_DrawMenuScreen; + menus[i].height = Widget_HeightFullScreen; + menus[i].width = Widget_WidthFullScreen; + menus[i].title = title; + menus[i].subtitle = buffer[i]; + menus[i].bgStamp.origin.x = 0; + menus[i].bgStamp.origin.y = 0; + menus[i].bgStamp.frame = SetAbsFrameIndex (setup_frame, menu_bgs[i]); + menus[i].num_children = menu_sizes[i]; + menus[i].child = menu_widgets[i]; + menus[i].highlighted = 0; + } + + /* Options */ + if (SplitString (GetStringAddress (SetAbsStringTableIndex (SetupTab, 2)), '\n', 100, buffer, bank) != CHOICE_COUNT) + { + /* TODO: Ignore extras instead of dying. */ + fprintf (stderr, "PANIC: Incorrect number of Choice Options\n"); + exit (1); + } + + for (i = 0; i < CHOICE_COUNT; i++) + { + choices[i].parent = NULL; + choices[i].handleEvent = Widget_HandleEventChoice; + choices[i].receiveFocus = Widget_ReceiveFocusChoice; + choices[i].draw = Widget_DrawChoice; + choices[i].height = Widget_HeightChoice; + choices[i].width = Widget_WidthFullScreen; + choices[i].category = buffer[i]; + choices[i].numopts = 0; + choices[i].options = NULL; + choices[i].selected = 0; + choices[i].highlighted = 0; + choices[i].maxcolumns = choice_widths[i]; + } + + /* Fill in the options now */ + index = 3; /* Index into string table */ + for (i = 0; i < CHOICE_COUNT; i++) + { + int j, optcount; + + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading choices\n"); + exit (1); + } + str = GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)); + optcount = SplitString (str, '\n', 100, buffer, bank); + choices[i].numopts = optcount; + choices[i].options = HMalloc (optcount * sizeof (CHOICE_OPTION)); + for (j = 0; j < optcount; j++) + { + choices[i].options[j].optname = buffer[j]; + choices[i].options[j].tooltip[0] = ""; + choices[i].options[j].tooltip[1] = ""; + choices[i].options[j].tooltip[2] = ""; + } + for (j = 0; j < optcount; j++) + { + int k, tipcount; + + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading choices\n"); + exit (1); + } + str = GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)); + tipcount = SplitString (str, '\n', 100, buffer, bank); + if (tipcount > 3) + { + tipcount = 3; + } + for (k = 0; k < tipcount; k++) + { + choices[i].options[j].tooltip[k] = buffer[k]; + } + } + } + + /* The first choice is resolution, and is handled specially */ + choices[0].numopts = RES_OPTS; + + /* Sliders */ + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading sliders\n"); + exit (1); + } + + if (SplitString (GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)), '\n', 100, buffer, bank) != SLIDER_COUNT) + { + /* TODO: Ignore extras instead of dying. */ + fprintf (stderr, "PANIC: Incorrect number of Slider Options\n"); + exit (1); + } + + for (i = 0; i < SLIDER_COUNT; i++) + { + sliders[i].parent = NULL; + sliders[i].handleEvent = Widget_HandleEventSlider; + sliders[i].receiveFocus = Widget_ReceiveFocusSimple; + sliders[i].draw = Widget_DrawSlider; + sliders[i].height = Widget_HeightOneLine; + sliders[i].width = Widget_WidthFullScreen; + sliders[i].draw_value = Widget_Slider_DrawValue; + sliders[i].min = 0; + sliders[i].max = 100; + sliders[i].step = 5; + sliders[i].value = 75; + sliders[i].category = buffer[i]; + sliders[i].tooltip[0] = ""; + sliders[i].tooltip[1] = ""; + sliders[i].tooltip[2] = ""; + } + + for (i = 0; i < SLIDER_COUNT; i++) + { + int j, tipcount; + + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading sliders\n"); + exit (1); + } + str = GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)); + tipcount = SplitString (str, '\n', 100, buffer, bank); + if (tipcount > 3) + { + tipcount = 3; + } + for (j = 0; j < tipcount; j++) + { + sliders[i].tooltip[j] = buffer[j]; + } + } + + /* Buttons */ + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading buttons\n"); + exit (1); + } + + if (SplitString (GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)), '\n', 100, buffer, bank) != BUTTON_COUNT) + { + /* TODO: Ignore extras instead of dying. */ + fprintf (stderr, "PANIC: Incorrect number of Button Options\n"); + exit (1); + } + + for (i = 0; i < BUTTON_COUNT; i++) + { + buttons[i].parent = NULL; + buttons[i].handleEvent = button_handlers[i]; + buttons[i].receiveFocus = Widget_ReceiveFocusSimple; + buttons[i].draw = Widget_DrawButton; + buttons[i].height = Widget_HeightOneLine; + buttons[i].width = Widget_WidthFullScreen; + buttons[i].name = buffer[i]; + buttons[i].tooltip[0] = ""; + buttons[i].tooltip[1] = ""; + buttons[i].tooltip[2] = ""; + } + + for (i = 0; i < BUTTON_COUNT; i++) + { + int j, tipcount; + + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading buttons\n"); + exit (1); + } + str = GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)); + tipcount = SplitString (str, '\n', 100, buffer, bank); + if (tipcount > 3) + { + tipcount = 3; + } + for (j = 0; j < tipcount; j++) + { + buttons[i].tooltip[j] = buffer[j]; + } + } + + /* Labels */ + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading labels\n"); + exit (1); + } + + if (SplitString (GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)), '\n', 100, buffer, bank) != LABEL_COUNT) + { + /* TODO: Ignore extras instead of dying. */ + fprintf (stderr, "PANIC: Incorrect number of Label Options\n"); + exit (1); + } + + for (i = 0; i < LABEL_COUNT; i++) + { + labels[i].parent = NULL; + labels[i].handleEvent = Widget_HandleEventIgnoreAll; + labels[i].receiveFocus = Widget_ReceiveFocusRefuseFocus; + labels[i].draw = Widget_DrawLabel; + labels[i].height = Widget_HeightLabel; + labels[i].width = Widget_WidthFullScreen; + labels[i].line_count = 0; + labels[i].lines = NULL; + } + + for (i = 0; i < LABEL_COUNT; i++) + { + int j, linecount; + + if (index >= count) + { + fprintf (stderr, "PANIC: String table cut short while reading labels\n"); + exit (1); + } + str = GetStringAddress (SetAbsStringTableIndex (SetupTab, index++)); + linecount = SplitString (str, '\n', 100, buffer, bank); + labels[i].line_count = linecount; + labels[i].lines = (const char **)HMalloc(linecount * sizeof(const char *)); + for (j = 0; j < linecount; j++) + { + labels[i].lines[j] = buffer[j]; + } + } + + /* Check for garbage at the end */ + if (index < count) + { + fprintf (stderr, "WARNING: Setup strings had %d garbage entries at the end.\n", count - index); + } +} + +static void +clean_up_widgets (void) +{ + int i; + + for (i = 0; i < CHOICE_COUNT; i++) + { + if (choices[i].options) + { + HFree (choices[i].options); + } + } + + for (i = 0; i < LABEL_COUNT; i++) + { + if (labels[i].lines) + { + HFree (labels[i].lines); + } + } + + /* Clear out the master tables */ + + if (SetupTab) + { + DestroyStringTable (ReleaseStringTable (SetupTab)); + SetupTab = 0; + } + if (bank) + { + StringBank_Free (bank); + bank = NULL; + } + if (setup_frame) + { + DestroyDrawable (ReleaseDrawable (setup_frame)); + setup_frame = NULL; + } +} + void SetupMenu (void) { @@ -742,11 +722,12 @@ SetupMenu (void) SetupTab = CaptureStringTable (LoadStringTable (SETUP_MENU_STRTAB)); if (SetupTab) { - fprintf (stderr, "GetStringTableCount reports %d entries.\n", GetStringTableCount (SetupTab)); + init_widgets (); } else { - fprintf (stderr, "Could not find setup strings!\n"); + fprintf (stderr, "PANIC: Could not find strings for the setup menu!\n"); + exit (1); } done = FALSE; @@ -755,8 +736,7 @@ SetupMenu (void) PropagateResults (); if (SetupTab) { - DestroyStringTable (ReleaseStringTable (SetupTab)); - SetupTab = 0; + clean_up_widgets (); } }