[options] Refactor INI options

This change introduces a new class to handle all of the INI options
data, VbamOption. A VbamOption represents a single option in the INI
file. It is not constructible outside of its implementation, which
prevents the initialization of incorrectly formatted options.

Internally, a VbamOption points to a global variable in memory, which
holds the value used at runtime. This is because various parts of the
codebase edit the global variable rather than going through a central
registry. This also means we need to separately update the INI values.

In the future, we may be able to convert all existing reads and writes
to the global variable to go through VbamOption. Individual UX elements
could link directly to getters/setters for a specific VbamOption rather
than have duplicate data.

VbamOption replaces the opt_desc struct and the global opts array. All
users of opt_desc and the global opts array have been updated.

This is a necessary preliminary change to better support a refactor of
accelerators, through wxUserInput.

Issue: #745, #158
This commit is contained in:
Fabrice de Gans 2022-09-06 21:18:27 -07:00 committed by Rafael Kitover
parent dd6071e5cb
commit c4d46a713f
12 changed files with 2285 additions and 671 deletions

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-09-21 17:52+0000\n"
"POT-Creation-Date: 2022-09-06 21:07-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -17,55 +17,55 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
#: wxvbam.cpp:225
#: wxvbam.cpp:227
msgid "visualboyadvance-m"
msgstr ""
#: wxvbam.cpp:446
#: wxvbam.cpp:448
msgid "Could not create main window"
msgstr ""
#: wxvbam.cpp:517
#: wxvbam.cpp:519
msgid "Save built-in XRC file and exit"
msgstr ""
#: wxvbam.cpp:520
#: wxvbam.cpp:522
msgid "Save built-in vba-over.ini and exit"
msgstr ""
#: wxvbam.cpp:523
#: wxvbam.cpp:525
msgid "Print configuration path and exit"
msgstr ""
#: wxvbam.cpp:526
#: wxvbam.cpp:528
msgid "Start in full-screen mode"
msgstr ""
#: wxvbam.cpp:529
#: wxvbam.cpp:531
msgid "Set a configuration file"
msgstr ""
#: wxvbam.cpp:533
#: wxvbam.cpp:535
msgid "Delete shared link state first, if it exists"
msgstr ""
#: wxvbam.cpp:540
#: wxvbam.cpp:542
msgid "List all settable options and exit"
msgstr ""
#: wxvbam.cpp:543
#: wxvbam.cpp:545
msgid "ROM file"
msgstr ""
#: wxvbam.cpp:545
#: wxvbam.cpp:547
msgid "<config>=<value>"
msgstr ""
#: wxvbam.cpp:576
#: wxvbam.cpp:578
msgid "Configuration/build error: can't find built-in xrc"
msgstr ""
#: wxvbam.cpp:584
#: wxvbam.cpp:586
#, c-format
msgid ""
"Wrote built-in configuration to %s.\n"
@ -74,11 +74,11 @@ msgid ""
"built-in:"
msgstr ""
#: wxvbam.cpp:599
#: wxvbam.cpp:601
msgid "Configuration is read from, in order:"
msgstr ""
#: wxvbam.cpp:613
#: wxvbam.cpp:615
#, c-format
msgid ""
"Wrote built-in override file to %s\n"
@ -86,13 +86,13 @@ msgid ""
"from search path:"
msgstr ""
#: wxvbam.cpp:619
#: wxvbam.cpp:621
msgid ""
"\n"
"\tbuilt-in"
msgstr ""
#: wxvbam.cpp:630
#: wxvbam.cpp:636
msgid ""
"Options set from the command line are saved if any configuration changes are "
"made in the user interface.\n"
@ -101,255 +101,255 @@ msgid ""
"\n"
msgstr ""
#: wxvbam.cpp:651
#: wxvbam.cpp:644
msgid ""
"The commands available for the Keyboard/* option are:\n"
"\n"
msgstr ""
#: wxvbam.cpp:663
#: wxvbam.cpp:655
msgid "Configuration file not found."
msgstr ""
#: wxvbam.cpp:696
#: wxvbam.cpp:688
msgid "Bad configuration option or multiple ROM files given:\n"
msgstr ""
#: guiinit.cpp:83
#: guiinit.cpp:84
msgid "Start!"
msgstr ""
#: guiinit.cpp:102 xrc/NetLink.xrc:99
#: guiinit.cpp:103 xrc/NetLink.xrc:99
msgid "Connect"
msgstr ""
#: guiinit.cpp:119
#: guiinit.cpp:120
msgid "You must enter a valid host name"
msgstr ""
#: guiinit.cpp:120
#: guiinit.cpp:121
msgid "Host name invalid"
msgstr ""
#: guiinit.cpp:138
#: guiinit.cpp:139
msgid "Waiting for clients..."
msgstr ""
#: guiinit.cpp:139
#: guiinit.cpp:140
#, c-format
msgid "Server IP address is: %s\n"
msgstr ""
#: guiinit.cpp:141
#: guiinit.cpp:142
msgid "Waiting for connection..."
msgstr ""
#: guiinit.cpp:142
#: guiinit.cpp:143
#, c-format
msgid "Connecting to %s\n"
msgstr ""
#: guiinit.cpp:175
#: guiinit.cpp:176
msgid ""
"Error occurred.\n"
"Please try again."
msgstr ""
#: guiinit.cpp:242 guiinit.cpp:295
#: guiinit.cpp:243 guiinit.cpp:296
msgid "Select cheat file"
msgstr ""
#: guiinit.cpp:243
#: guiinit.cpp:244
msgid "VBA cheat lists (*.clt)|*.clt|CHT cheat lists (*.cht)|*.cht"
msgstr ""
#: guiinit.cpp:262 panel.cpp:449
#: guiinit.cpp:263 panel.cpp:449
msgid "Loaded cheats"
msgstr ""
#: guiinit.cpp:296
#: guiinit.cpp:297
msgid "VBA cheat lists (*.clt)|*.clt"
msgstr ""
#: guiinit.cpp:314
#: guiinit.cpp:315
msgid "Saved cheats"
msgstr ""
#: guiinit.cpp:345 guiinit.cpp:364
#: guiinit.cpp:346 guiinit.cpp:365
msgid "Restore old values?"
msgstr ""
#: guiinit.cpp:346 guiinit.cpp:365
#: guiinit.cpp:347 guiinit.cpp:366
msgid "Removing cheats"
msgstr ""
#: guiinit.cpp:756 xrc/JoyPanel.xrc:364
#: guiinit.cpp:757 xrc/JoyPanel.xrc:364
msgid "GameShark"
msgstr ""
#: guiinit.cpp:757 cmdevents.cpp:678
#: guiinit.cpp:758 cmdevents.cpp:675
msgid "GameGenie"
msgstr ""
#: guiinit.cpp:759
#: guiinit.cpp:760
msgid "Generic Code"
msgstr ""
#: guiinit.cpp:760
#: guiinit.cpp:761
msgid "GameShark Advance"
msgstr ""
#: guiinit.cpp:761
#: guiinit.cpp:762
msgid "CodeBreaker Advance"
msgstr ""
#: guiinit.cpp:762
#: guiinit.cpp:763
msgid "Flashcart CHT"
msgstr ""
#: guiinit.cpp:830 guiinit.cpp:1085
#: guiinit.cpp:831 guiinit.cpp:1086
msgid "Number cannot be empty"
msgstr ""
#: guiinit.cpp:868
#: guiinit.cpp:869
#, c-format
msgid "Search produced %d results. Please refine better"
msgstr ""
#: guiinit.cpp:880
#: guiinit.cpp:881
msgid "Search produced no results"
msgstr ""
#: guiinit.cpp:1043
#: guiinit.cpp:1044
msgid "8-bit "
msgstr ""
#: guiinit.cpp:1047
#: guiinit.cpp:1048
msgid "16-bit "
msgstr ""
#: guiinit.cpp:1051
#: guiinit.cpp:1052
msgid "32-bit "
msgstr ""
#: guiinit.cpp:1057
#: guiinit.cpp:1058
msgid "signed decimal"
msgstr ""
#: guiinit.cpp:1061
#: guiinit.cpp:1062
msgid "unsigned decimal"
msgstr ""
#: guiinit.cpp:1065
#: guiinit.cpp:1066
msgid "unsigned hexadecimal"
msgstr ""
#: guiinit.cpp:1543
#: guiinit.cpp:1544
#, c-format
msgid "%d frames = %.2f ms"
msgstr ""
#: guiinit.cpp:1555
#: guiinit.cpp:1556
msgid "Default device"
msgstr ""
#: guiinit.cpp:1726
#: guiinit.cpp:1727
msgid "Desktop mode"
msgstr ""
#: guiinit.cpp:1733
#: guiinit.cpp:1734
#, c-format
msgid "%d x %d - %dbpp @ %dHz"
msgstr ""
#: guiinit.cpp:1846 cmdevents.cpp:748 xrc/DisplayConfig.xrc:85
#: guiinit.cpp:1847 cmdevents.cpp:745 xrc/DisplayConfig.xrc:85
#: xrc/DisplayConfig.xrc:135 xrc/DisplayConfig.xrc:221
#: xrc/GameBoyAdvanceConfig.xrc:32 xrc/GameBoyAdvanceConfig.xrc:204
#: xrc/SoundConfig.xrc:219 xrc/SoundConfig.xrc:309
msgid "None"
msgstr ""
#: guiinit.cpp:1887
#: guiinit.cpp:1888
#, c-format
msgid "No usable rpi plugins found in %s"
msgstr ""
#: guiinit.cpp:1907 xrc/DisplayConfig.xrc:107
#: guiinit.cpp:1908 xrc/DisplayConfig.xrc:107
msgid "Plugin"
msgstr ""
#: guiinit.cpp:1935
#: guiinit.cpp:1936
msgid "Please select a plugin or a different filter"
msgstr ""
#: guiinit.cpp:1936
#: guiinit.cpp:1937
msgid "Plugin selection error"
msgstr ""
#: guiinit.cpp:2149
#: guiinit.cpp:2150
msgid "This will clear all user-defined accelerators. Are you sure?"
msgstr ""
#: guiinit.cpp:2149
#: guiinit.cpp:2150
msgid "Confirm"
msgstr ""
#: guiinit.cpp:2740
#: guiinit.cpp:2741
msgid "Main icon not found"
msgstr ""
#: guiinit.cpp:2750
#: guiinit.cpp:2751
msgid "Browse"
msgstr ""
#: guiinit.cpp:2764
#: guiinit.cpp:2765
msgid "Main display panel not found"
msgstr ""
#: guiinit.cpp:2941
#: guiinit.cpp:2942
#, c-format
msgid "Duplicate menu accelerator: %s for %s and %s; keeping first"
msgstr ""
#: guiinit.cpp:2955
#: guiinit.cpp:2956
#, c-format
msgid "Menu accelerator %s for %s overrides default for %s ; keeping menu"
msgstr ""
#: guiinit.cpp:3094
#: guiinit.cpp:3097
#, c-format
msgid "Invalid menu item %s; removing"
msgstr ""
#: guiinit.cpp:3302
#: guiinit.cpp:3305
msgid "Code"
msgstr ""
#: guiinit.cpp:3311
#: guiinit.cpp:3314
msgid "Description"
msgstr ""
#: guiinit.cpp:3385 xrc/CheatAdd.xrc:31
#: guiinit.cpp:3388 xrc/CheatAdd.xrc:31
msgid "Address"
msgstr ""
#: guiinit.cpp:3386
#: guiinit.cpp:3389
msgid "Old Value"
msgstr ""
#: guiinit.cpp:3387
#: guiinit.cpp:3390
msgid "New Value"
msgstr ""
#: guiinit.cpp:3918
#: guiinit.cpp:3917
msgid "Menu commands"
msgstr ""
#: guiinit.cpp:3941
#: guiinit.cpp:3940
msgid "Other commands"
msgstr ""
#: guiinit.cpp:4052
#: guiinit.cpp:4051
msgid "JoyBus host invalid; disabling"
msgstr ""
@ -851,29 +851,19 @@ msgstr ""
msgid "Network is not supported in local mode."
msgstr ""
#: opts.cpp:649 opts.cpp:951
#, c-format
msgid "Invalid value %s for option %s; valid values are %s%s%s"
msgstr ""
#: opts.cpp:666 opts.cpp:963
#, c-format
msgid "Invalid value %d for option %s; valid values are %d - %d"
msgstr ""
#: opts.cpp:673 opts.cpp:682 opts.cpp:971 opts.cpp:979
#, c-format
msgid "Invalid value %f for option %s; valid values are %f - %f"
msgstr ""
#: opts.cpp:739 opts.cpp:760 opts.cpp:1047
#: opts.cpp:492 opts.cpp:513 opts.cpp:745
#, c-format
msgid "Invalid key binding %s for %s"
msgstr ""
#: opts.cpp:934
#: opts.cpp:668 opts.cpp:677 opts.cpp:686 opts.cpp:695 vbam-options.cpp:313
#, c-format
msgid "Invalid flag option %s - %s ignored"
msgid "Invalid value %s for option %s"
msgstr ""
#: opts.cpp:767
#, c-format
msgid "Unknown option %s with value %s"
msgstr ""
#: sys.cpp:195 sys.cpp:256
@ -1110,6 +1100,456 @@ msgstr ""
msgid "Error in video recording (%s); aborting"
msgstr ""
#: vbam-options.cpp:218
#, c-format
msgid "Invalid value %f for option %s; valid values are %f - %f"
msgstr ""
#: vbam-options.cpp:232 vbam-options.cpp:246
#, c-format
msgid "Invalid value %d for option %s; valid values are %d - %d"
msgstr ""
#: vbam-options.cpp:297
#, c-format
msgid "Invalid value %d for option %s; valid values are %s"
msgstr ""
#: vbam-options-static.cpp:342
msgid "Use bilinear filter with 3d renderer"
msgstr ""
#: vbam-options-static.cpp:343
msgid "Full-screen filter to apply"
msgstr ""
#: vbam-options-static.cpp:344
msgid "Filter plugin library"
msgstr ""
#: vbam-options-static.cpp:345
msgid "Interframe blending function"
msgstr ""
#: vbam-options-static.cpp:346
msgid "Keep window on top"
msgstr ""
#: vbam-options-static.cpp:347
msgid "Maximum number of threads to run filters in"
msgstr ""
#: vbam-options-static.cpp:348
msgid "Render method; if unsupported, simple method will be used"
msgstr ""
#: vbam-options-static.cpp:349
msgid "Default scale factor"
msgstr ""
#: vbam-options-static.cpp:350
msgid "Retain aspect ratio when resizing"
msgstr ""
#: vbam-options-static.cpp:353
msgid "BIOS file to use for GB, if enabled"
msgstr ""
#: vbam-options-static.cpp:354
msgid "GB color enhancement, if enabled"
msgstr ""
#: vbam-options-static.cpp:355
msgid "Enable DX Colorization Hacks"
msgstr ""
#: vbam-options-static.cpp:356 vbam-options-static.cpp:368
msgid "Apply LCD filter, if enabled"
msgstr ""
#: vbam-options-static.cpp:357
msgid "BIOS file to use for GBC, if enabled"
msgstr ""
#: vbam-options-static.cpp:358
msgid ""
"The default palette, as 8 comma-separated 4-digit hex integers (rgb555)."
msgstr ""
#: vbam-options-static.cpp:359
msgid ""
"The first user palette, as 8 comma-separated 4-digit hex integers (rgb555)."
msgstr ""
#: vbam-options-static.cpp:360
msgid ""
"The second user palette, as 8 comma-separated 4-digit hex integers (rgb555)."
msgstr ""
#: vbam-options-static.cpp:361
msgid "Automatically gather a full page before printing"
msgstr ""
#: vbam-options-static.cpp:362
msgid "Automatically save printouts as screen captures with -print suffix"
msgstr ""
#: vbam-options-static.cpp:363 vbam-options-static.cpp:379
msgid "Directory to look for ROM files"
msgstr ""
#: vbam-options-static.cpp:364
msgid "Directory to look for GBC ROM files"
msgstr ""
#: vbam-options-static.cpp:367
msgid "BIOS file to use, if enabled"
msgstr ""
#: vbam-options-static.cpp:370
msgid "Enable link at boot"
msgstr ""
#: vbam-options-static.cpp:371
msgid "Enable faster network protocol by default"
msgstr ""
#: vbam-options-static.cpp:372
msgid "Default network link client host"
msgstr ""
#: vbam-options-static.cpp:373
msgid "Default network link server IP to bind"
msgstr ""
#: vbam-options-static.cpp:374
msgid "Default network link port (server and client)"
msgstr ""
#: vbam-options-static.cpp:375
msgid "Default network protocol"
msgstr ""
#: vbam-options-static.cpp:376
msgid "Link timeout (ms)"
msgstr ""
#: vbam-options-static.cpp:377
msgid "Link cable type"
msgstr ""
#: vbam-options-static.cpp:382
msgid "Automatically load last saved state"
msgstr ""
#: vbam-options-static.cpp:383
msgid ""
"Directory to store game save files (relative paths are relative to ROM; "
"blank is config dir)"
msgstr ""
#: vbam-options-static.cpp:384
msgid "Freeze recent load list"
msgstr ""
#: vbam-options-static.cpp:385
msgid ""
"Directory to store A/V and game recordings (relative paths are relative to "
"ROM)"
msgstr ""
#: vbam-options-static.cpp:386
msgid "Number of seconds between rewind snapshots (0 to disable)"
msgstr ""
#: vbam-options-static.cpp:387
msgid "Directory to store screenshots (relative paths are relative to ROM)"
msgstr ""
#: vbam-options-static.cpp:388
msgid ""
"Directory to store saved state files (relative paths are relative to "
"BatteryDir)"
msgstr ""
#: vbam-options-static.cpp:389
msgid "Enable status bar"
msgstr ""
#: vbam-options-static.cpp:392
msgid ""
"The parameter Joypad/<n>/<button> contains a comma-separated list of key "
"names which map to joypad #<n> button <button>. Button is one of Up, Down, "
"Left, Right, A, B, L, R, Select, Start, MotionUp, MotionDown, MotionLeft, "
"MotionRight, AutoA, AutoB, Speed, Capture, GS"
msgstr ""
#: vbam-options-static.cpp:393
msgid "The autofire toggle period, in frames (1/60 s)"
msgstr ""
#: vbam-options-static.cpp:394
msgid "The number of the stick to use in single-player mode"
msgstr ""
#: vbam-options-static.cpp:397
msgid ""
"The parameter Keyboard/<cmd> contains a comma-separated list of key names (e."
"g. Alt-Shift-F1). When the named key is pressed, the command <cmd> is "
"executed."
msgstr ""
#: vbam-options-static.cpp:400
msgid "Enable AGB debug print"
msgstr ""
#: vbam-options-static.cpp:401
msgid "Auto skip frames."
msgstr ""
#: vbam-options-static.cpp:402
msgid "Apply IPS/UPS/IPF patches if found"
msgstr ""
#: vbam-options-static.cpp:403
msgid "Automatically save and load cheat list"
msgstr ""
#: vbam-options-static.cpp:404
msgid "Automatically enable border for Super GameBoy games"
msgstr ""
#: vbam-options-static.cpp:405
msgid "Always enable border"
msgstr ""
#: vbam-options-static.cpp:406
msgid "Screen capture file format"
msgstr ""
#: vbam-options-static.cpp:407
msgid "Enable cheats"
msgstr ""
#: vbam-options-static.cpp:409 xrc/MainMenu.xrc:355
msgid "Enable MMX"
msgstr ""
#: vbam-options-static.cpp:411
msgid "Disable on-screen status messages"
msgstr ""
#: vbam-options-static.cpp:412
msgid "Type of system to emulate"
msgstr ""
#: vbam-options-static.cpp:413
msgid "Flash size 0 = 64KB 1 = 128KB"
msgstr ""
#: vbam-options-static.cpp:414
msgid "Skip frames. Values are 0-9 or -1 to skip automatically based on time."
msgstr ""
#: vbam-options-static.cpp:415
msgid "Fullscreen mode color depth (0 = any)"
msgstr ""
#: vbam-options-static.cpp:416
msgid "Fullscreen mode frequency (0 = any)"
msgstr ""
#: vbam-options-static.cpp:417
msgid "Fullscreen mode height (0 = desktop)"
msgstr ""
#: vbam-options-static.cpp:418
msgid "Fullscreen mode width (0 = desktop)"
msgstr ""
#: vbam-options-static.cpp:419
msgid "The palette to use"
msgstr ""
#: vbam-options-static.cpp:420
msgid "Enable printer emulation"
msgstr ""
#: vbam-options-static.cpp:421
msgid "Break into GDB after loading the game."
msgstr ""
#: vbam-options-static.cpp:422
msgid "Port to connect GDB to."
msgstr ""
#: vbam-options-static.cpp:424
msgid "Number of players in network"
msgstr ""
#: vbam-options-static.cpp:426
msgid "Maximum scale factor (0 = no limit)"
msgstr ""
#: vbam-options-static.cpp:427
msgid "Pause game when main window loses focus"
msgstr ""
#: vbam-options-static.cpp:428
msgid "Enable RTC (vba-over.ini override is rtcEnabled"
msgstr ""
#: vbam-options-static.cpp:429
msgid "Native save (\"battery\") hardware type"
msgstr ""
#: vbam-options-static.cpp:430
msgid "Show speed indicator"
msgstr ""
#: vbam-options-static.cpp:431
msgid "Draw on-screen messages transparently"
msgstr ""
#: vbam-options-static.cpp:432
msgid "Skip BIOS initialization"
msgstr ""
#: vbam-options-static.cpp:433
msgid "Do not overwrite cheat list when loading state"
msgstr ""
#: vbam-options-static.cpp:434
msgid "Do not overwrite native (battery) save when loading state"
msgstr ""
#: vbam-options-static.cpp:435
msgid "Throttle game speed, even when accelerated (0-450%, 0 = no throttle)"
msgstr ""
#: vbam-options-static.cpp:436
msgid "Set throttle for speedup key (0-3000%, 0 = no throttle)"
msgstr ""
#: vbam-options-static.cpp:437
msgid "Number of frames to skip with speedup (instead of speedup throttle)"
msgstr ""
#: vbam-options-static.cpp:438
msgid "Use frame skip for speedup throttle"
msgstr ""
#: vbam-options-static.cpp:439
msgid "Use the specified BIOS file for GB"
msgstr ""
#: vbam-options-static.cpp:440
msgid "Use the specified BIOS file"
msgstr ""
#: vbam-options-static.cpp:441
msgid "Use the specified BIOS file for GBC"
msgstr ""
#: vbam-options-static.cpp:442
msgid "Wait for vertical sync"
msgstr ""
#: vbam-options-static.cpp:445
msgid "Enter fullscreen mode at startup"
msgstr ""
#: vbam-options-static.cpp:446
msgid "Window maximized"
msgstr ""
#: vbam-options-static.cpp:447
msgid "Window height at startup"
msgstr ""
#: vbam-options-static.cpp:448
msgid "Window width at startup"
msgstr ""
#: vbam-options-static.cpp:449
msgid "Window axis X position at startup"
msgstr ""
#: vbam-options-static.cpp:450
msgid "Window axis Y position at startup"
msgstr ""
#: vbam-options-static.cpp:453
msgid "Capture key events while on background"
msgstr ""
#: vbam-options-static.cpp:454
msgid "Capture joy events while on background"
msgstr ""
#: vbam-options-static.cpp:455
msgid "Hide menu bar when mouse is inactive"
msgstr ""
#: vbam-options-static.cpp:458
msgid "Sound API; if unsupported, default API will be used"
msgstr ""
#: vbam-options-static.cpp:459
msgid "Device ID of chosen audio device for chosen driver"
msgstr ""
#: vbam-options-static.cpp:460
msgid "Number of sound buffers"
msgstr ""
#: vbam-options-static.cpp:461
msgid "Bit mask of sound channels to enable"
msgstr ""
#: vbam-options-static.cpp:462
msgid "GBA sound filtering (%)"
msgstr ""
#: vbam-options-static.cpp:463
msgid "GBA sound interpolation"
msgstr ""
#: vbam-options-static.cpp:464
msgid "GB sound declicking"
msgstr ""
#: vbam-options-static.cpp:465
msgid "GB echo effect (%)"
msgstr ""
#: vbam-options-static.cpp:466
msgid "Enable GB sound effects"
msgstr ""
#: vbam-options-static.cpp:467
msgid "GB stereo effect (%)"
msgstr ""
#: vbam-options-static.cpp:468
msgid "GB surround sound effect (%)"
msgstr ""
#: vbam-options-static.cpp:469
msgid "Sound sample rate (kHz)"
msgstr ""
#: vbam-options-static.cpp:470
msgid "Sound volume (%)"
msgstr ""
#: vbam-options-static.cpp:669 vbam-options-static.cpp:688
#: vbam-options-static.cpp:711 vbam-options-static.cpp:732
#: vbam-options-static.cpp:752
#, c-format
msgid "Invalid value %s for option %s; valid values are %s"
msgstr ""
#: viewsupt.cpp:776
msgid "R:"
msgstr ""
@ -3024,10 +3464,6 @@ msgstr ""
msgid "&Retain aspect ratio"
msgstr ""
#: xrc/MainMenu.xrc:355
msgid "Enable MMX"
msgstr ""
#: xrc/MainMenu.xrc:360
msgid "&Bilinear filter"
msgstr ""

View File

@ -733,6 +733,8 @@ set(
opts.cpp
sys.cpp
panel.cpp
vbam-options.cpp
vbam-options-static.cpp
viewsupt.cpp
wayland.cpp
strutils.cpp
@ -767,6 +769,8 @@ set(
filters.h
ioregs.h
opts.h
vbam-options.h
vbam-options-internal.h
viewsupt.h
wxhead.h
wayland.h

View File

@ -31,10 +31,10 @@ bool cmditem_lt(const struct cmditem& cmd1, const struct cmditem& cmd2)
return wxStrcmp(cmd1.cmd, cmd2.cmd) < 0;
}
void MainFrame::GetMenuOptionBool(const char* menuName, bool& field)
void MainFrame::GetMenuOptionBool(const wxString& menuName, bool field)
{
field = !field;
int id = wxXmlResource::GetXRCID(wxString(menuName, wxConvUTF8));
int id = wxXmlResource::GetXRCID(menuName);
for (size_t i = 0; i < checkable_mi.size(); i++) {
if (checkable_mi[i].cmd != id)
@ -45,11 +45,11 @@ void MainFrame::GetMenuOptionBool(const char* menuName, bool& field)
}
}
void MainFrame::GetMenuOptionInt(const char* menuName, int& field, int mask)
void MainFrame::GetMenuOptionInt(const wxString& menuName, int field, int mask)
{
int value = mask;
bool is_checked = ((field) & (mask)) != (value);
int id = wxXmlResource::GetXRCID(wxString(menuName, wxConvUTF8));
int id = wxXmlResource::GetXRCID(menuName);
for (size_t i = 0; i < checkable_mi.size(); i++) {
if (checkable_mi[i].cmd != id)
@ -62,9 +62,9 @@ void MainFrame::GetMenuOptionInt(const char* menuName, int& field, int mask)
field = ((field) & ~(mask)) | (is_checked ? (value) : 0);
}
void MainFrame::SetMenuOption(const char* menuName, int value)
void MainFrame::SetMenuOption(const wxString& menuName, int value)
{
int id = wxXmlResource::GetXRCID(wxString(menuName, wxConvUTF8));
int id = wxXmlResource::GetXRCID(menuName);
for (size_t i = 0; i < checkable_mi.size(); i++) {
if (checkable_mi[i].cmd != id)

View File

@ -24,6 +24,7 @@
#include <wx/wfstream.h>
#include "opts.h"
#include "vbam-options.h"
#include "wx/gamecontrol.h"
#include "wx/userinput.h"
#include "../gba/CheatSearch.h"
@ -2651,30 +2652,30 @@ void MainFrame::set_global_accels()
SetRecentAccels();
}
void MainFrame::MenuOptionBool(const char* menuName, bool& field)
void MainFrame::MenuOptionBool(const wxString& menuName, bool field)
{
int id = wxXmlResource::GetXRCID(wxString(menuName, wxConvUTF8));
int id = wxXmlResource::GetXRCID(menuName);
for (size_t i = 0; i < checkable_mi.size(); i++) {
if (checkable_mi[i].cmd != id)
continue;
checkable_mi[i].boolopt = &field;
checkable_mi[i].initialized = true;
checkable_mi[i].mi->Check(field);
break;
}
}
void MainFrame::MenuOptionIntMask(const char* menuName, int& field, int mask)
void MainFrame::MenuOptionIntMask(const wxString& menuName, int field, int mask)
{
int id = wxXmlResource::GetXRCID(wxString(menuName, wxConvUTF8));
int id = wxXmlResource::GetXRCID(menuName);
int value = mask;
for (size_t i = 0; i < checkable_mi.size(); i++) {
if (checkable_mi[i].cmd != id)
continue;
checkable_mi[i].intopt = &field;
checkable_mi[i].initialized = true;
checkable_mi[i].mask = mask;
checkable_mi[i].val = value;
checkable_mi[i].mi->Check((field & mask) == value);
@ -2682,15 +2683,15 @@ void MainFrame::MenuOptionIntMask(const char* menuName, int& field, int mask)
}
}
void MainFrame::MenuOptionIntRadioValue(const char* menuName, int& field, int value)
void MainFrame::MenuOptionIntRadioValue(const wxString& menuName, int field, int value)
{
int id = wxXmlResource::GetXRCID(wxString(menuName, wxConvUTF8));
int id = wxXmlResource::GetXRCID(menuName);
for (size_t i = 0; i < checkable_mi.size(); i++) {
if (checkable_mi[i].cmd != id)
continue;
checkable_mi[i].intopt = &field;
checkable_mi[i].initialized = true;
checkable_mi[i].val = field;
checkable_mi[i].mi->Check(field == value);
break;
@ -2973,17 +2974,14 @@ bool MainFrame::BindControls()
// store checkable items
if (mi->IsCheckable()) {
checkable_mi_t cmi = { cmdtab[i].cmd_id, mi, NULL, NULL, 0, 0 };
checkable_mi_t cmi = { cmdtab[i].cmd_id, mi, 0, 0 };
checkable_mi.push_back(cmi);
for (int j = 0; j < num_opts; j++) {
wxString menuName = wxString(opts[j].cmd, wxConvUTF8);
if (menuName == cmdtab[i].cmd) {
if (opts[j].intopt)
MenuOptionIntMask(opts[j].cmd, *opts[j].intopt, (1 << 0));
else if (opts[j].boolopt)
MenuOptionBool(opts[j].cmd, *opts[j].boolopt);
for (const VbamOption& option : VbamOption::AllOptions()) {
if (option.is_int()) {
MenuOptionIntMask(option.command(), option.GetInt(), (1 << 0));
} else if (option.is_bool()) {
MenuOptionBool(option.command(), option.GetBool());
}
}
}
@ -3090,7 +3088,7 @@ bool MainFrame::BindControls()
}
for (size_t i = 0; i < checkable_mi.size(); i++)
if (!checkable_mi[i].boolopt && !checkable_mi[i].intopt) {
if (!checkable_mi[i].initialized) {
wxLogError(_("Invalid menu item %s; removing"),
checkable_mi[i].mi->GetItemLabelText().c_str());
checkable_mi[i].mi->GetMenu()->Remove(checkable_mi[i].mi);

View File

@ -1,10 +1,11 @@
#include "opts.h"
#include <vector>
#include <algorithm>
#include <wx/log.h>
#include <wx/display.h>
#include "wx/gamecontrol.h"
#include "wx/userinput.h"
#include "vbam-options.h"
#include "wxvbam.h"
#include "strutils.h"
@ -19,29 +20,6 @@
#define WJKB wxUserInput::FromLegacyKeyModJoy
/* not sure how well other compilers support field-init syntax */
#define STROPT(c, n, d, v) \
new_opt_desc(wxT(c), (n), d, &v)
#define INTOPT(c, n, d, v, min, max) \
new_opt_desc(wxT(c), (n), d, NULL, &v, wxT(""), min, max)
#define DOUBLEOPT(c, n, d, v, min, max) \
new_opt_desc(wxT(c), (n), d, NULL, NULL, wxT(""), min, max, NULL, &v)
#define UINTOPT(c, n, d, v, min, max) \
new_opt_desc(wxT(c), (n), d, NULL, NULL, wxT(""), min, max, NULL, NULL, &v)
#define BOOLOPT(c, n, d, v) \
new_opt_desc(wxT(c), (n), d, NULL, NULL, wxT(""), 0, 0, &v)
#define ENUMOPT(c, n, d, v, e) \
new_opt_desc(wxT(c), (n), d, NULL, &v, e)
#define NOOPT(c, n, d) \
new_opt_desc(c, (n), d)
opts_t gopts;
// having the standard menu accels here means they will work even without menus
@ -272,167 +250,6 @@ const std::map<wxGameControl, std::set<wxUserInput>> kDefaultBindings = {
wxAcceleratorEntry_v sys_accels;
// Initializer for struct opt_desc
opt_desc new_opt_desc(wxString opt, const char* cmd, wxString desc,
wxString* stropt, int* intopt, wxString enumvals,
double min, double max, bool* boolopt,
double* doubleopt, uint32_t* uintopt, wxString curstr,
int curint, double curdouble, uint32_t curuint)
{
struct opt_desc new_opt = {opt, cmd, desc, stropt, intopt, enumvals,
min, max, boolopt, doubleopt, uintopt,
curstr, curint, curdouble, curuint};
return new_opt;
}
// Note: this table must be sorted in option name order
// Both for better user display and for (fast) searching by name
opt_desc opts[] = {
/// Display
BOOLOPT("Display/Bilinear", "Bilinear", wxTRANSLATE("Use bilinear filter with 3d renderer"), gopts.bilinear),
ENUMOPT("Display/Filter", "", wxTRANSLATE("Full-screen filter to apply"), gopts.filter,
wxTRANSLATE("none|2xsai|super2xsai|supereagle|pixelate|advmame|"
L"bilinear|bilinearplus|scanlines|tvmode|hq2x|lq2x|"
L"simple2x|simple3x|hq3x|simple4x|hq4x|xbrz2x|xbrz3x|xbrz4x|xbrz5x|xbrz6x|plugin")),
STROPT("Display/FilterPlugin", "", wxTRANSLATE("Filter plugin library"), gopts.filter_plugin),
ENUMOPT("Display/IFB", "", wxTRANSLATE("Interframe blending function"), gopts.ifb, wxTRANSLATE("none|smart|motionblur")),
BOOLOPT("Display/KeepOnTop", "KeepOnTop", wxTRANSLATE("Keep window on top"), gopts.keep_on_top),
INTOPT("Display/MaxThreads", "Multithread", wxTRANSLATE("Maximum number of threads to run filters in"), gopts.max_threads, 1, 256),
#ifdef __WXMSW__
ENUMOPT("Display/RenderMethod", "", wxTRANSLATE("Render method; if unsupported, simple method will be used"), gopts.render_method, wxTRANSLATE("simple|opengl|direct3d")),
#elif defined(__WXMAC__)
ENUMOPT("Display/RenderMethod", "", wxTRANSLATE("Render method; if unsupported, simple method will be used"), gopts.render_method, wxTRANSLATE("simple|opengl|quartz2d")),
#else
ENUMOPT("Display/RenderMethod", "", wxTRANSLATE("Render method; if unsupported, simple method will be used"), gopts.render_method, wxTRANSLATE("simple|opengl")),
#endif
DOUBLEOPT("Display/Scale", "", wxTRANSLATE("Default scale factor"), gopts.video_scale, 1, 6),
BOOLOPT("Display/Stretch", "RetainAspect", wxTRANSLATE("Retain aspect ratio when resizing"), gopts.retain_aspect),
/// GB
STROPT("GB/BiosFile", "", wxTRANSLATE("BIOS file to use for GB, if enabled"), gopts.gb_bios),
INTOPT("GB/ColorOption", "GBColorOption", wxTRANSLATE("GB color enhancement, if enabled"), gbColorOption, 0, 1),
INTOPT("GB/ColorizerHack", "ColorizerHack", wxTRANSLATE("Enable DX Colorization Hacks"), colorizerHack, 0, 1),
BOOLOPT("GB/LCDFilter", "GBLcdFilter", wxTRANSLATE("Apply LCD filter, if enabled"), gbLcdFilter),
STROPT("GB/GBCBiosFile", "", wxTRANSLATE("BIOS file to use for GBC, if enabled"), gopts.gbc_bios),
NOOPT(wxT("GB/Palette0"), "", wxTRANSLATE("The default palette, as 8 comma-separated 4-digit hex integers (rgb555).")),
NOOPT(wxT("GB/Palette1"), "", wxTRANSLATE("The first user palette, as 8 comma-separated 4-digit hex integers (rgb555).")),
NOOPT(wxT("GB/Palette2"), "", wxTRANSLATE("The second user palette, as 8 comma-separated 4-digit hex integers (rgb555).")),
BOOLOPT("GB/PrintAutoPage", "PrintGather", wxTRANSLATE("Automatically gather a full page before printing"), gopts.print_auto_page),
BOOLOPT("GB/PrintScreenCap", "PrintSnap", wxTRANSLATE("Automatically save printouts as screen captures with -print suffix"), gopts.print_screen_cap),
STROPT("GB/ROMDir", "", wxTRANSLATE("Directory to look for ROM files"), gopts.gb_rom_dir),
STROPT("GB/GBCROMDir", "", wxTRANSLATE("Directory to look for GBC ROM files"), gopts.gbc_rom_dir),
/// GBA
STROPT("GBA/BiosFile", "", wxTRANSLATE("BIOS file to use, if enabled"), gopts.gba_bios),
BOOLOPT("GBA/LCDFilter", "GBALcdFilter", wxTRANSLATE("Apply LCD filter, if enabled"), gbaLcdFilter),
#ifndef NO_LINK
BOOLOPT("GBA/LinkAuto", "LinkAuto", wxTRANSLATE("Enable link at boot"), gopts.link_auto),
INTOPT("GBA/LinkFast", "SpeedOn", wxTRANSLATE("Enable faster network protocol by default"), linkHacks, 0, 1),
STROPT("GBA/LinkHost", "", wxTRANSLATE("Default network link client host"), gopts.link_host),
STROPT("GBA/ServerIP", "", wxTRANSLATE("Default network link server IP to bind"), gopts.server_ip),
UINTOPT("GBA/LinkPort", "", wxTRANSLATE("Default network link port (server and client)"), gopts.link_port, 0, 65535),
INTOPT("GBA/LinkProto", "LinkProto", wxTRANSLATE("Default network protocol"), gopts.link_proto, 0, 1),
INTOPT("GBA/LinkTimeout", "LinkTimeout", wxTRANSLATE("Link timeout (ms)"), linkTimeout, 0, 9999999),
INTOPT("GBA/LinkType", "LinkType", wxTRANSLATE("Link cable type"), gopts.gba_link_type, 0, 5),
#endif
STROPT("GBA/ROMDir", "", wxTRANSLATE("Directory to look for ROM files"), gopts.gba_rom_dir),
/// General
BOOLOPT("General/AutoLoadLastState", "", wxTRANSLATE("Automatically load last saved state"), gopts.autoload_state),
STROPT("General/BatteryDir", "", wxTRANSLATE("Directory to store game save files (relative paths are relative to ROM; blank is config dir)"), gopts.battery_dir),
BOOLOPT("General/FreezeRecent", "", wxTRANSLATE("Freeze recent load list"), gopts.recent_freeze),
STROPT("General/RecordingDir", "", wxTRANSLATE("Directory to store A/V and game recordings (relative paths are relative to ROM)"), gopts.recording_dir),
INTOPT("General/RewindInterval", "", wxTRANSLATE("Number of seconds between rewind snapshots (0 to disable)"), gopts.rewind_interval, 0, 600),
STROPT("General/ScreenshotDir", "", wxTRANSLATE("Directory to store screenshots (relative paths are relative to ROM)"), gopts.scrshot_dir),
STROPT("General/StateDir", "", wxTRANSLATE("Directory to store saved state files (relative paths are relative to BatteryDir)"), gopts.state_dir),
INTOPT("General/StatusBar", "StatusBar", wxTRANSLATE("Enable status bar"), gopts.statusbar, 0, 1),
/// Joypad
NOOPT(wxT("Joypad/*/*"), "", wxTRANSLATE("The parameter Joypad/<n>/<button> contains a comma-separated list of key names which map to joypad #<n> button <button>. Button is one of Up, Down, Left, Right, A, B, L, R, Select, Start, MotionUp, MotionDown, MotionLeft, MotionRight, AutoA, AutoB, Speed, Capture, GS")),
INTOPT("Joypad/AutofireThrottle", "", wxTRANSLATE("The autofire toggle period, in frames (1/60 s)"), gopts.autofire_rate, 1, 1000),
/// Keyboard
INTOPT("Joypad/Default", "", wxTRANSLATE("The number of the stick to use in single-player mode"), gopts.default_stick, 1, 4),
/// Keyboard
NOOPT(wxT("Keyboard/*"), "", wxTRANSLATE("The parameter Keyboard/<cmd> contains a comma-separated list of key names (e.g. Alt-Shift-F1). When the named key is pressed, the command <cmd> is executed.")),
// Core
INTOPT("preferences/agbPrint", "AGBPrinter", wxTRANSLATE("Enable AGB debug print"), agbPrint, 0, 1),
INTOPT("preferences/autoFrameSkip", "FrameSkipAuto", wxTRANSLATE("Auto skip frames."), autoFrameSkip, 0, 1),
INTOPT("preferences/autoPatch", "ApplyPatches", wxTRANSLATE("Apply IPS/UPS/IPF patches if found"), autoPatch, 0, 1),
BOOLOPT("preferences/autoSaveLoadCheatList", "", wxTRANSLATE("Automatically save and load cheat list"), gopts.autoload_cheats),
INTOPT("preferences/borderAutomatic", "", wxTRANSLATE("Automatically enable border for Super GameBoy games"), gbBorderAutomatic, 0, 1),
INTOPT("preferences/borderOn", "", wxTRANSLATE("Always enable border"), gbBorderOn, 0, 1),
INTOPT("preferences/captureFormat", "", wxTRANSLATE("Screen capture file format"), captureFormat, 0, 1),
INTOPT("preferences/cheatsEnabled", "", wxTRANSLATE("Enable cheats"), cheatsEnabled, 0, 1),
#ifdef MMX
INTOPT("preferences/enableMMX", "MMX", wxTRANSLATE("Enable MMX"), enableMMX, 0, 1),
#endif
INTOPT("preferences/disableStatus", "NoStatusMsg", wxTRANSLATE("Disable on-screen status messages"), disableStatusMessages, 0, 1),
INTOPT("preferences/emulatorType", "", wxTRANSLATE("Type of system to emulate"), gbEmulatorType, 0, 5),
INTOPT("preferences/flashSize", "", wxTRANSLATE("Flash size 0 = 64KB 1 = 128KB"), optFlashSize, 0, 1),
INTOPT("preferences/frameSkip", "FrameSkip", wxTRANSLATE("Skip frames. Values are 0-9 or -1 to skip automatically based on time."), frameSkip, -1, 9),
INTOPT("preferences/fsColorDepth", "", wxTRANSLATE("Fullscreen mode color depth (0 = any)"), fsColorDepth, 0, 999),
INTOPT("preferences/fsFrequency", "", wxTRANSLATE("Fullscreen mode frequency (0 = any)"), fsFrequency, 0, 999),
INTOPT("preferences/fsHeight", "", wxTRANSLATE("Fullscreen mode height (0 = desktop)"), fsHeight, 0, 99999),
INTOPT("preferences/fsWidth", "", wxTRANSLATE("Fullscreen mode width (0 = desktop)"), fsWidth, 0, 99999),
INTOPT("preferences/gbPaletteOption", "", wxTRANSLATE("The palette to use"), gbPaletteOption, 0, 2),
INTOPT("preferences/gbPrinter", "Printer", wxTRANSLATE("Enable printer emulation"), winGbPrinterEnabled, 0, 1),
INTOPT("preferences/gdbBreakOnLoad", "DebugGDBBreakOnLoad", wxTRANSLATE("Break into GDB after loading the game."), gdbBreakOnLoad, 0, 1),
INTOPT("preferences/gdbPort", "DebugGDBPort", wxTRANSLATE("Port to connect GDB to."), gdbPort, 0, 65535),
#ifndef NO_LINK
INTOPT("preferences/LinkNumPlayers", "", wxTRANSLATE("Number of players in network"), linkNumPlayers, 2, 4),
#endif
INTOPT("preferences/maxScale", "", wxTRANSLATE("Maximum scale factor (0 = no limit)"), maxScale, 0, 100),
INTOPT("preferences/pauseWhenInactive", "PauseWhenInactive", wxTRANSLATE("Pause game when main window loses focus"), pauseWhenInactive, 0, 1),
INTOPT("preferences/rtcEnabled", "RTC", wxTRANSLATE("Enable RTC (vba-over.ini override is rtcEnabled"), rtcEnabled, 0, 1),
INTOPT("preferences/saveType", "", wxTRANSLATE("Native save (\"battery\") hardware type"), cpuSaveType, 0, 5),
INTOPT("preferences/showSpeed", "", wxTRANSLATE("Show speed indicator"), showSpeed, 0, 2),
INTOPT("preferences/showSpeedTransparent", "Transparent", wxTRANSLATE("Draw on-screen messages transparently"), showSpeedTransparent, 0, 1),
INTOPT("preferences/skipBios", "SkipIntro", wxTRANSLATE("Skip BIOS initialization"), skipBios, 0, 1),
INTOPT("preferences/skipSaveGameCheats", "", wxTRANSLATE("Do not overwrite cheat list when loading state"), skipSaveGameCheats, 0, 1),
INTOPT("preferences/skipSaveGameBattery", "", wxTRANSLATE("Do not overwrite native (battery) save when loading state"), skipSaveGameBattery, 0, 1),
UINTOPT("preferences/throttle", "", wxTRANSLATE("Throttle game speed, even when accelerated (0-450%, 0 = no throttle)"), throttle, 0, 450),
UINTOPT("preferences/speedupThrottle", "", wxTRANSLATE("Set throttle for speedup key (0-3000%, 0 = no throttle)"), speedup_throttle, 0, 3000),
UINTOPT("preferences/speedupFrameSkip", "", wxTRANSLATE("Number of frames to skip with speedup (instead of speedup throttle)"), speedup_frame_skip, 0, 300),
BOOLOPT("preferences/speedupThrottleFrameSkip", "", wxTRANSLATE("Use frame skip for speedup throttle"), speedup_throttle_frame_skip),
INTOPT("preferences/useBiosGB", "BootRomGB", wxTRANSLATE("Use the specified BIOS file for GB"), useBiosFileGB, 0, 1),
INTOPT("preferences/useBiosGBA", "BootRomEn", wxTRANSLATE("Use the specified BIOS file"), useBiosFileGBA, 0, 1),
INTOPT("preferences/useBiosGBC", "BootRomGBC", wxTRANSLATE("Use the specified BIOS file for GBC"), useBiosFileGBC, 0, 1),
INTOPT("preferences/vsync", "VSync", wxTRANSLATE("Wait for vertical sync"), vsync, 0, 1),
/// Geometry
INTOPT("geometry/fullScreen", "Fullscreen", wxTRANSLATE("Enter fullscreen mode at startup"), fullScreen, 0, 1),
INTOPT("geometry/isMaximized", "Maximized", wxTRANSLATE("Window maximized"), windowMaximized, 0, 1),
UINTOPT("geometry/windowHeight", "Height", wxTRANSLATE("Window height at startup"), windowHeight, 0, 99999),
UINTOPT("geometry/windowWidth", "Width", wxTRANSLATE("Window width at startup"), windowWidth, 0, 99999),
INTOPT("geometry/windowX", "X", wxTRANSLATE("Window axis X position at startup"), windowPositionX, -1, 99999),
INTOPT("geometry/windowY", "Y", wxTRANSLATE("Window axis Y position at startup"), windowPositionY, -1, 99999),
/// UI
BOOLOPT("ui/allowKeyboardBackgroundInput", "AllowKeyboardBackgroundInput", wxTRANSLATE("Capture key events while on background"), allowKeyboardBackgroundInput),
BOOLOPT("ui/allowJoystickBackgroundInput", "AllowJoystickBackgroundInput", wxTRANSLATE("Capture joy events while on background"), allowJoystickBackgroundInput),
BOOLOPT("ui/hideMenuBar", "", wxTRANSLATE("Hide menu bar when mouse is inactive"), gopts.hide_menu_bar),
/// Sound
ENUMOPT("Sound/AudioAPI", "", wxTRANSLATE("Sound API; if unsupported, default API will be used"), gopts.audio_api, wxTRANSLATE("sdl|openal|directsound|xaudio2|faudio")),
STROPT("Sound/AudioDevice", "", wxTRANSLATE("Device ID of chosen audio device for chosen driver"), gopts.audio_dev),
INTOPT("Sound/Buffers", "", wxTRANSLATE("Number of sound buffers"), gopts.audio_buffers, 2, 10),
INTOPT("Sound/Enable", "", wxTRANSLATE("Bit mask of sound channels to enable"), gopts.sound_en, 0, 0x30f),
INTOPT("Sound/GBAFiltering", "", wxTRANSLATE("GBA sound filtering (%)"), gopts.gba_sound_filter, 0, 100),
BOOLOPT("Sound/GBAInterpolation", "GBASoundInterpolation", wxTRANSLATE("GBA sound interpolation"), soundInterpolation),
BOOLOPT("Sound/GBDeclicking", "GBDeclicking", wxTRANSLATE("GB sound declicking"), gopts.gb_declick),
INTOPT("Sound/GBEcho", "", wxTRANSLATE("GB echo effect (%)"), gopts.gb_echo, 0, 100),
BOOLOPT("Sound/GBEnableEffects", "GBEnhanceSound", wxTRANSLATE("Enable GB sound effects"), gopts.gb_effects_config_enabled),
INTOPT("Sound/GBStereo", "", wxTRANSLATE("GB stereo effect (%)"), gopts.gb_stereo, 0, 100),
BOOLOPT("Sound/GBSurround", "GBSurround", wxTRANSLATE("GB surround sound effect (%)"), gopts.gb_effects_config_surround),
ENUMOPT("Sound/Quality", "", wxTRANSLATE("Sound sample rate (kHz)"), gopts.sound_qual, wxTRANSLATE("48|44|22|11")),
INTOPT("Sound/Volume", "", wxTRANSLATE("Sound volume (%)"), gopts.sound_vol, 0, 200)
};
const int num_opts = sizeof(opts) / sizeof(opts[0]);
// This constructor only works with globally allocated gopts. It relies on
// the default value of every non-object to be 0.
opts_t::opts_t()
@ -482,28 +299,15 @@ opts_t::opts_t()
skipSaveGameBattery = true;
}
// for binary_search() and friends
bool opt_lt(const opt_desc& opt1, const opt_desc& opt2)
{
return wxStrcmp(opt1.opt, opt2.opt) < 0;
}
// FIXME: simulate MakeInstanceFilename(vbam.ini) using subkeys (Slave%d/*)
void load_opts()
{
// just for sanity...
bool did_init = false;
if (did_init)
return;
did_init = true;
// Translations can't be initialized in static structures (before locale
// is initialized), so do them now
for (int i = 0; i < num_opts; i++)
opts[i].desc = wxGetTranslation(opts[i].desc);
// enumvals should not be translated, since they would cause config file
// change after lang change
// instead, translate when presented to user
@ -525,7 +329,6 @@ void load_opts()
// Date of last online update check;
gopts.last_update = cfg->Read(wxT("General/LastUpdated"), (long)0);
cfg->Read(wxT("General/LastUpdatedFileName"), &gopts.last_updated_filename);
std::sort(&opts[0], &opts[num_opts], opt_lt);
for (cont = cfg->GetFirstGroup(s, grp_idx); cont;
cont = cfg->GetNextGroup(s, grp_idx)) {
@ -599,14 +402,10 @@ void load_opts()
} else {
s.append(wxT('/'));
s.append(e);
opt_desc dummy = new_opt_desc(s);
wxString opt_name(dummy.opt);
if (!std::binary_search(&opts[0], &opts[num_opts], dummy, opt_lt) && opt_name != wxT("General/LastUpdated") && opt_name != wxT("General/LastUpdatedFileName")) {
if (!VbamOption::FindOptionByName(s) && s != wxT("General/LastUpdated") && s != wxT("General/LastUpdatedFileName")) {
//wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str());
item_del.push_back(s);
}
s.resize(poff);
}
}
@ -624,107 +423,61 @@ void load_opts()
// config file will be updated with unset options
cfg->SetRecordDefaults();
for (int i = 0; i < num_opts; i++) {
opt_desc& opt = opts[i];
if (opt.stropt) {
//Fix provided by nhdailey
cfg->Read(opt.opt, opt.stropt, *opt.stropt);
opt.curstr = *opt.stropt;
} else if (!opt.enumvals.empty()) {
auto enum_opts = strutils::split(opt.enumvals.MakeLower(), wxT("|"));
opt.curint = *opt.intopt;
bool gotit = cfg->Read(opt.opt, &s); s.MakeLower();
if (gotit && !s.empty()) {
const auto found_pos = enum_opts.Index(s);
const bool matched = ((int)found_pos != wxNOT_FOUND);
if (!matched) {
opt.curint = 0;
const wxString ev = opt.enumvals;
const wxString evx = wxGetTranslation(ev);
bool isx = wxStrcmp(ev, evx) != 0;
// technically, the translation for this string could incorproate
// the equals sign if necessary instead of doing it this way
wxLogWarning(_("Invalid value %s for option %s; valid values are %s%s%s"),
s.c_str(), opt.opt.c_str(), ev.c_str(),
isx ? wxT(" = ") : wxEmptyString,
isx ? evx.c_str() : wxEmptyString);
// write first option
cfg->Write(opt.opt, enum_opts[0]);
} else
opt.curint = found_pos;
*opt.intopt = opt.curint;
} else {
cfg->Write(opt.opt, enum_opts[opt.curint]);
// First access here will also initialize translations.
for (const VbamOption& opt : VbamOption::AllOptions()) {
switch (opt.type()) {
case VbamOption::Type::kNone:
// Keyboard or Joystick. Handled separately for now.
break;
case VbamOption::Type::kBool: {
bool temp;
cfg->Read(opt.config_name(), &temp, opt.GetBool());
opt.SetBool(temp);
break;
}
case VbamOption::Type::kDouble: {
double temp;
cfg->Read(opt.config_name(), &temp, opt.GetDouble());
opt.SetDouble(temp);
break;
}
case VbamOption::Type::kInt: {
int32_t temp;
cfg->Read(opt.config_name(), &temp, opt.GetInt());
opt.SetInt(temp);
break;
}
case VbamOption::Type::kUnsigned: {
int temp;
cfg->Read(opt.config_name(), &temp, opt.GetUnsigned());
opt.SetUnsigned(temp);
break;
}
case VbamOption::Type::kString: {
wxString temp;
cfg->Read(opt.config_name(), &temp, opt.GetString());
opt.SetString(temp);
break;
}
case VbamOption::Type::kFilter:
case VbamOption::Type::kInterframe:
case VbamOption::Type::kRenderMethod:
case VbamOption::Type::kAudioApi:
case VbamOption::Type::kSoundQuality: {
wxString temp;
if (cfg->Read(opt.config_name(), &temp) && !temp.empty()) {
opt.SetEnumString(temp.MakeLower());
}
} else if (opt.intopt) {
cfg->Read(opt.opt, &opt.curint, *opt.intopt);
if (opt.curint < opt.min || opt.curint > opt.max) {
wxLogWarning(_("Invalid value %d for option %s; valid values are %d - %d"), opt.curint, opt.opt.c_str(), int(opt.min), int(opt.max));
} else
*opt.intopt = opt.curint;
} else if (opt.doubleopt) {
cfg->Read(opt.opt, &opt.curdouble, *opt.doubleopt);
if (opt.curdouble < opt.min || opt.curdouble > opt.max) {
wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), opt.curdouble, opt.opt.c_str(), opt.min, opt.max);
} else
*opt.doubleopt = opt.curdouble;
} else if (opt.uintopt) {
int val;
cfg->Read(opt.opt, &val, *opt.uintopt);
opt.curuint = val;
if (opt.curuint < opt.min || opt.curuint > opt.max) {
wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), opt.curuint, opt.opt.c_str(), opt.min, opt.max);
} else
*opt.uintopt = opt.curuint;
} else if (opt.boolopt) {
cfg->Read(opt.opt, opt.boolopt, *opt.boolopt);
opt.curbool = *opt.boolopt;
// This is necessary, in case the option we loaded was invalid.
cfg->Write(opt.config_name(), opt.GetEnumString());
break;
}
}
// GB/Palette[0-2] is special
for (int i = 0; i < 3; i++) {
wxString optn;
optn.Printf(wxT("GB/Palette%d"), i);
wxString val;
const opt_desc dummy = new_opt_desc(optn);
opt_desc* opt = std::lower_bound(&opts[0], &opts[num_opts], dummy, opt_lt);
wxString entry;
for (int j = 0; j < 8; j++) {
// stupid wxString.Printf doesn't support printing at offset
entry.Printf(wxT("%04X,"), (int)systemGbPalette[i * 8 + j]);
val.append(entry);
case VbamOption::Type::kGbPalette: {
wxString temp;
cfg->Read(opt.config_name(), &temp, opt.GetGbPaletteString());
opt.SetGbPalette(temp);
break;
}
val.resize(val.size() - 1);
cfg->Read(optn, &val, val);
opt->curstr = val;
for (int j = 0, cpos = 0; j < 8; j++) {
int start = cpos;
cpos = val.find(wxT(','), cpos);
if ((size_t)cpos == wxString::npos)
cpos = val.size();
long ival;
// ignoring errors; if the value is bad, palette will be corrupt
// -- tough.
// stupid wxString.ToLong doesn't support start @ offset
entry = val.substr(start, cpos - start);
entry.ToLong(&ival, 16);
systemGbPalette[i * 8 + j] = ival;
if ((size_t)cpos != val.size())
cpos++;
}
}
@ -785,57 +538,36 @@ void update_opts()
{
wxFileConfig* cfg = wxGetApp().cfg;
for (int i = 0; i < num_opts; i++) {
opt_desc& opt = opts[i];
if (opt.stropt) {
if (opt.curstr != *opt.stropt) {
opt.curstr = *opt.stropt;
cfg->Write(opt.opt, opt.curstr);
}
} else if (!opt.enumvals.empty()) {
if (*opt.intopt != opt.curint) {
opt.curint = *opt.intopt;
auto enum_opts = strutils::split(opt.enumvals.MakeLower(), wxT("|"));
cfg->Write(opt.opt, enum_opts[opt.curint]);
}
} else if (opt.intopt) {
if (*opt.intopt != opt.curint)
cfg->Write(opt.opt, (opt.curint = *opt.intopt));
} else if (opt.doubleopt) {
if (*opt.doubleopt != opt.curdouble)
cfg->Write(opt.opt, (opt.curdouble = *opt.doubleopt));
} else if (opt.uintopt) {
if (*opt.uintopt != opt.curuint)
cfg->Write(opt.opt, (long)(opt.curuint = *opt.uintopt));
} else if (opt.boolopt) {
if (*opt.boolopt != opt.curbool)
cfg->Write(opt.opt, (opt.curbool = *opt.boolopt));
}
}
// gbpalette requires doing the conversion to string over
// it may trigger a write even with no changes if # of digits changes
for (int i = 0; i < 3; i++) {
wxString optn;
optn.Printf(wxT("GB/Palette%d"), i);
const opt_desc dummy = new_opt_desc(optn);
opt_desc* opt = std::lower_bound(&opts[0], &opts[num_opts], dummy, opt_lt);
wxString val;
wxString entry;
for (int j = 0; j < 8; j++) {
// stupid wxString.Printf doesn't support printing at offset
entry.Printf(wxT("%04X,"), (int)systemGbPalette[i * 8 + j]);
val.append(entry);
}
val.resize(val.size() - 1);
if (val != opt->curstr) {
opt->curstr = val;
cfg->Write(optn, val);
for (const VbamOption& opt : VbamOption::AllOptions()) {
switch (opt.type()) {
case VbamOption::Type::kNone:
// Keyboard and Joypad are handled separately.
break;
case VbamOption::Type::kBool:
cfg->Write(opt.config_name(), opt.GetBool());
break;
case VbamOption::Type::kDouble:
cfg->Write(opt.config_name(), opt.GetDouble());
break;
case VbamOption::Type::kInt:
cfg->Write(opt.config_name(), opt.GetInt());
break;
case VbamOption::Type::kUnsigned:
cfg->Write(opt.config_name(), opt.GetUnsigned());
break;
case VbamOption::Type::kString:
cfg->Write(opt.config_name(), opt.GetString());
break;
case VbamOption::Type::kFilter:
case VbamOption::Type::kInterframe:
case VbamOption::Type::kRenderMethod:
case VbamOption::Type::kAudioApi:
case VbamOption::Type::kSoundQuality:
cfg->Write(opt.config_name(), opt.GetEnumString());
break;
case VbamOption::Type::kGbPalette:
cfg->Write(opt.config_name(), opt.GetGbPaletteString());
break;
}
}
@ -922,149 +654,116 @@ void update_opts()
cfg->Flush();
}
bool opt_set(const wxString& name, const wxString& val)
{
const opt_desc dummy = new_opt_desc(name);
const opt_desc* opt = std::lower_bound(&opts[0], &opts[num_opts], dummy, opt_lt);
void opt_set(const wxString& name, const wxString& val) {
VbamOption const* opt = VbamOption::FindOptionByName(name);
if (!wxStrcmp(name, opt->opt)) {
if (opt->stropt)
*opt->stropt = wxString(val);
else if (opt->boolopt) {
if (!(val == wxT('0') || val == wxT('1')))
wxLogWarning(_("Invalid flag option %s - %s ignored"),
// opt->is_none() means it is Keyboard or Joypad.
if (opt && !opt->is_none()) {
switch (opt->type()) {
case VbamOption::Type::kNone:
// This should never happen.
assert(false);
return;
case VbamOption::Type::kBool:
if (val != '0' && val != '1') {
wxLogWarning(_("Invalid value %s for option %s"),
name.c_str(), val.c_str());
else
*opt->boolopt = val == wxT('1');
} else if (!opt->enumvals.empty()) {
wxString s = val; s.MakeLower();
wxString ev = opt->enumvals; ev.MakeLower();
auto enum_opts = strutils::split(ev, wxT("|"));
const std::size_t found_pos = enum_opts.Index(s);
const bool matched = ((int)found_pos != wxNOT_FOUND);
if (!matched) {
const wxString evx = wxGetTranslation(opt->enumvals);
bool isx = wxStrcmp(opt->enumvals, evx) != 0;
// technically, the translation for this string could incorproate
// the equals sign if necessary instead of doing it this way
wxLogWarning(_("Invalid value %s for option %s; valid values are %s%s%s"),
s.c_str(), opt->opt.c_str(), opt->enumvals.c_str(),
isx ? wxT(" = ") : wxEmptyString,
isx ? evx.c_str() : wxEmptyString);
} else {
*opt->intopt = found_pos;
return;
}
} else if (opt->intopt) {
const wxString s(val);
long ival;
if (!s.ToLong(&ival) || ival < opt->min || ival > opt->max)
wxLogWarning(_("Invalid value %d for option %s; valid values are %d - %d"), ival, name.c_str(), opt->min, opt->max);
else
*opt->intopt = ival;
} else if (opt->doubleopt) {
const wxString s(val);
double dval;
if (!s.ToDouble(&dval) || dval < opt->min || dval > opt->max)
wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), dval, name.c_str(), opt->min, opt->max);
else
*opt->doubleopt = dval;
} else if (opt->uintopt) {
const wxString s(val);
unsigned long uival;
if (!s.ToULong(&uival) || uival < opt->min || uival > opt->max)
wxLogWarning(_("Invalid value %f for option %s; valid values are %f - %f"), uival, name.c_str(), opt->min, opt->max);
else
*opt->uintopt = (uint32_t)uival;
} else {
// GB/Palette[0-2] is virtual
for (int i = 0; i < 3; i++) {
wxString optn;
optn.Printf(wxT("GB/Palette%d"), i);
if (optn != name)
continue;
wxString vals(val);
for (size_t j = 0, cpos = 0; j < 8; j++) {
int start = cpos;
cpos = vals.find(wxT(','), cpos);
if (cpos == wxString::npos)
cpos = vals.size();
long ival;
// ignoring errors; if the value is bad, palette will be corrupt
// -- tough.
// stupid wxString.ToLong doesn't support start @ offset
wxString entry = vals.substr(start, cpos - start);
entry.ToLong(&ival, 16);
systemGbPalette[i * 8 + j] = ival;
if (cpos != vals.size())
cpos++;
}
opt->SetBool(val == '1');
return;
case VbamOption::Type::kDouble: {
double value;
if (!val.ToDouble(&value)) {
wxLogWarning(_("Invalid value %s for option %s"), val, name.c_str());
return;
}
opt->SetDouble(value);
return;
}
return true;
} else {
if (name.Find(wxT('/')) == wxNOT_FOUND)
return false;
auto parts = strutils::split(name, wxT("/"));
if (parts[0] != wxT("Keyboard")) {
cmditem* cmd = std::lower_bound(&cmdtab[0], &cmdtab[ncmds], cmditem{parts[1],wxString(),0,0,NULL}, cmditem_lt);
if (cmd == &cmdtab[ncmds] || wxStrcmp(parts[1], cmd->cmd))
return false;
for (auto i = gopts.accels.begin(); i < gopts.accels.end(); ++i)
if (i->GetCommand() == cmd->cmd_id) {
auto j = i;
for (; j < gopts.accels.end(); ++j)
if (j->GetCommand() != cmd->cmd_id)
break;
gopts.accels.erase(i, j);
break;
}
if (!val.empty()) {
auto aval = wxJoyKeyTextCtrl::ToAccelFromString(val);
for (size_t i = 0; i < aval.size(); i++)
aval[i].Set(aval[i].GetUkey(), aval[i].GetJoystick(), aval[i].GetFlags(), aval[i].GetKeyCode(), cmd->cmd_id);
if (!aval.size())
wxLogWarning(_("Invalid key binding %s for %s"), val.c_str(), name.c_str());
else
gopts.accels.insert(gopts.accels.end(), aval.begin(), aval.end());
case VbamOption::Type::kInt: {
long value;
if (!val.ToLong(&value)) {
wxLogWarning(_("Invalid value %s for option %s"), val, name.c_str());
return;
}
return true;
opt->SetInt(static_cast<int32_t>(value));
return;
}
const nonstd::optional<wxGameControl> game_control =
wxGameControl::FromString(name);
if (game_control) {
if (val.empty()) {
gopts.game_control_bindings[game_control.value()].clear();
} else {
gopts.game_control_bindings[game_control.value()] =
wxUserInput::FromString(val);
case VbamOption::Type::kUnsigned: {
unsigned long value;
if (!val.ToULong(&value)) {
wxLogWarning(_("Invalid value %s for option %s"), val, name.c_str());
return;
}
return true;
opt->SetUnsigned(static_cast<uint32_t>(value));
return;
}
case VbamOption::Type::kString:
opt->SetString(val);
return;
case VbamOption::Type::kFilter:
case VbamOption::Type::kInterframe:
case VbamOption::Type::kRenderMethod:
case VbamOption::Type::kAudioApi:
case VbamOption::Type::kSoundQuality:
opt->SetEnumString(val);
return;
case VbamOption::Type::kGbPalette:
opt->SetGbPalette(val);
return;
}
return false;
}
if (name.Find(wxT('/')) == wxNOT_FOUND) {
return;
}
auto parts = strutils::split(name, wxT("/"));
if (parts[0] == wxT("Keyboard")) {
cmditem* cmd = std::lower_bound(&cmdtab[0], &cmdtab[ncmds], cmditem{parts[1],wxString(),0,0,NULL}, cmditem_lt);
if (cmd == &cmdtab[ncmds] || wxStrcmp(parts[1], cmd->cmd)) {
return;
}
for (auto i = gopts.accels.begin(); i < gopts.accels.end(); ++i)
if (i->GetCommand() == cmd->cmd_id) {
auto j = i;
for (; j < gopts.accels.end(); ++j)
if (j->GetCommand() != cmd->cmd_id)
break;
gopts.accels.erase(i, j);
break;
}
if (!val.empty()) {
auto aval = wxJoyKeyTextCtrl::ToAccelFromString(val);
for (size_t i = 0; i < aval.size(); i++) {
aval[i].Set(aval[i].GetUkey(), aval[i].GetJoystick(), aval[i].GetFlags(), aval[i].GetKeyCode(), cmd->cmd_id);
}
if (!aval.size()) {
wxLogWarning(_("Invalid key binding %s for %s"), val.c_str(), name.c_str());
return;
}
gopts.accels.insert(gopts.accels.end(), aval.begin(), aval.end());
}
return;
}
const nonstd::optional<wxGameControl> game_control =
wxGameControl::FromString(name);
if (game_control) {
if (val.empty()) {
gopts.game_control_bindings[game_control.value()].clear();
} else {
gopts.game_control_bindings[game_control.value()] =
wxUserInput::FromString(val);
}
return;
}
wxLogWarning(_("Unknown option %s with value %s"), name.c_str(), val.c_str());
}

View File

@ -98,34 +98,6 @@ extern struct opts_t {
// wxWidgets-generated options (opaque)
} gopts;
extern struct opt_desc {
wxString opt;
const char* cmd;
wxString desc;
wxString* stropt;
int* intopt;
wxString enumvals;
double min, max;
bool* boolopt;
double* doubleopt;
uint32_t* uintopt;
// current configured value
wxString curstr;
int curint;
double curdouble;
uint32_t curuint;
#define curbool curint
} opts[];
// Initializer for struct opt_desc
opt_desc new_opt_desc(wxString opt = wxT(""), const char* cmd = NULL, wxString desc = wxT(""),
wxString* stropt = NULL, int* intopt = NULL, wxString enumvals = wxT(""),
double min = 0, double max = 0, bool* boolopt = NULL,
double* doubleopt = NULL, uint32_t* uintopt = NULL, wxString curstr = wxT(""),
int curint = 0, double curdouble = 0, uint32_t curuint = 0);
extern const int num_opts;
extern const wxAcceleratorEntryUnicode default_accels[];
extern const int num_def_accels;
@ -137,6 +109,6 @@ void load_opts();
// will detect changes and write config if necessary
void update_opts();
// returns true if option name correct; prints error if val invalid
bool opt_set(const wxString& name, const wxString& val);
void opt_set(const wxString& name, const wxString& val);
#endif /* WX_OPTS_H */

View File

@ -0,0 +1,42 @@
#ifndef VBAM_OPTIONS_INTERNAL_INCLUDE
#error "Do not include "vbam-options-internal.h" outside of the implementation."
#endif
#include <array>
#include <string>
#include <wx/string.h>
#include "nonstd/optional.hpp"
#include "vbam-options.h"
namespace internal {
struct VbamOptionData {
const wxString config_name;
const wxString command;
const wxString ux_helper;
const VbamOption::Type type;
};
// Static data to initialize global values.;
extern const std::array<VbamOptionData, kNbOptions + 1> kAllOptionsData;
// Conversion utilities.
nonstd::optional<VbamOptionID> StringToOptionId(const wxString& input);
wxString FilterToString(int value);
wxString InterframeToString(int value);
wxString RenderMethodToString(int value);
wxString AudioApiToString(int value);
wxString SoundQualityToString(int value);
int StringToFilter(const wxString& config_name, const wxString& input);
int StringToInterframe(const wxString& config_name, const wxString& input);
int StringToRenderMethod(const wxString& config_name, const wxString& input);
int StringToAudioApi(const wxString& config_name, const wxString& input);
int StringToSoundQuality(const wxString& config_name, const wxString& input);
wxString AllEnumValuesForType(VbamOption::Type type);
// Max value for enum types.
int MaxForType(VbamOption::Type type);
} // namespace internal

View File

@ -0,0 +1,830 @@
#include "vbam-options.h"
// Helper implementation file to define and compile all of these huge constants
// separately. These should not be updated very often, so this improves
#include <algorithm>
#include <wx/log.h>
#include "../common/ConfigManager.h"
#include "../gb/gbGlobals.h"
#include "opts.h"
#include "wx/stringimpl.h"
#define VBAM_OPTIONS_INTERNAL_INCLUDE
#include "vbam-options-internal.h"
#undef VBAM_OPTIONS_INTERNAL_INCLUDE
namespace {
// This enum must be kept in sync with the one in wxvbam.h
enum class FilterFunction {
kNone,
k2xsai,
kSuper2xsai,
kSupereagle,
kPixelate,
kAdvmame,
kBilinear,
kBilinearplus,
kScanlines,
kTvmode,
kHQ2x,
kLQ2x,
kSimple2x,
kSimple3x,
kHQ3x,
kSimple4x,
kHQ4x,
kXbrz2x,
kXbrz3x,
kXbrz4x,
kXbrz5x,
kXbrz6x,
kPlugin, // This must always be last.
// Do not add anything under here.
kLast,
};
constexpr size_t kNbFilterFunctions = static_cast<size_t>(FilterFunction::kLast);
// These MUST follow the same order as the definitions of the enum above.
// Adding an option without adding to this array will result in a compiler
// error since kNbFilterFunctions is automatically updated.
static const std::array<wxString, kNbFilterFunctions> kFilterStrings = {
"none",
"2xsai",
"super2xsai",
"supereagle",
"pixelate",
"advmame",
"bilinear",
"bilinearplus",
"scanlines",
"tvmode",
"hq2x",
"lq2x",
"simple2x",
"simple3x",
"hq3x",
"simple4x",
"hq4x",
"xbrz2x",
"xbrz3x",
"xbrz4x",
"xbrz5x",
"xbrz6x",
"plugin",
};
// This enum must be kept in sync with the one in wxvbam.h
enum class Interframe {
kNone = 0,
kSmart,
kMotionBlur,
// Do not add anything under here.
kLast,
};
constexpr size_t kNbInterframes = static_cast<size_t>(Interframe::kLast);
// These MUST follow the same order as the definitions of the enum above.
// Adding an option without adding to this array will result in a compiler
// error since kNbInterframes is automatically updated.
static const std::array<wxString, kNbInterframes> kInterframeStrings = {
"none",
"smart",
"motionblur",
};
// This enum must be kept in sync with the one in wxvbam.h
enum class RenderMethod {
kSimple = 0,
kOpenGL,
#ifdef __WXMSW__
kDirect3d,
#elif defined(__WXMAC__)
kQuartz2d,
#endif
// Do not add anything under here.
kLast,
};
constexpr size_t kNbRenderMethods = static_cast<size_t>(RenderMethod::kLast);
// These MUST follow the same order as the definitions of the enum above.
// Adding an option without adding to this array will result in a compiler
// error since kNbRenderMethods is automatically updated.
static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = {
"simple",
"opengl",
#ifdef __WXMSW__
"direct3d",
#elif defined(__WXMAC__)
"quartz2d",
#endif
};
// This enum must be kept in sync with the one in wxvbam.h
enum class AudioApi {
kSdl = 0,
kOpenAL,
kDirectSound,
kXAudio2,
kFaudio,
// Do not add anything under here.
kLast,
};
constexpr size_t kNbAudioApis = static_cast<size_t>(AudioApi::kLast);
// These MUST follow the same order as the definitions of the enum above.
// Adding an option without adding to this array will result in a compiler
// error since kNbAudioApis is automatically updated.
static const std::array<wxString, kNbAudioApis> kAudioApiStrings = {
"sdl",
"openal",
"directsound",
"xaudio2",
"faudio",
};
enum class SoundQuality {
k48kHz = 0,
k44kHz,
k22kHz,
k11kHz,
// Do not add anything under here.
kLast,
};
constexpr size_t kNbSoundQualities = static_cast<size_t>(SoundQuality::kLast);
// These MUST follow the same order as the definitions of the enum above.
// Adding an option without adding to this array will result in a compiler
// error since kNbSoundQualities is automatically updated.
static const std::array<wxString, kNbSoundQualities> kSoundQualityStrings = {
"48",
"44",
"22",
"11",
};
// Builds the "all enum values" string for a given array defined above.
template<std::size_t SIZE>
wxString AllEnumValuesForArray(const std::array<wxString, SIZE>& input) {
// 15 characters per option is a reasonable higher bound. Probably.
static constexpr size_t kMaxOptionLength = 15u;
wxString all_options;
all_options.reserve(kMaxOptionLength * SIZE);
std::for_each(input.cbegin(), input.cend(), [&all_options](const auto& elt) {
all_options.append(elt);
all_options.append('|');
});
// Remove last value
all_options.RemoveLast(1u);
return all_options;
}
} // namespace
// static
std::array<VbamOption, kNbOptions>& VbamOption::AllOptions() {
// These MUST follow the same order as the definitions in VbamOptionID.
// Adding an option without adding to this array will result in a compiler
// error since kNbOptions is automatically updated.
// This will be initialized on the first call, in load_opts(), ensuring the
// translation initialization has already happened.
static std::array<VbamOption, kNbOptions> g_all_opts = {
/// Display
VbamOption(VbamOptionID::kDisplayBilinear, &gopts.bilinear),
VbamOption(VbamOptionID::kDisplayFilter, &gopts.filter),
VbamOption(VbamOptionID::kDisplayFilterPlugin, &gopts.filter_plugin),
VbamOption(VbamOptionID::kDisplayIFB, &gopts.ifb),
VbamOption(VbamOptionID::kDisplayKeepOnTop, &gopts.keep_on_top),
VbamOption(VbamOptionID::kDisplayMaxThreads, &gopts.max_threads, 1, 256),
VbamOption(VbamOptionID::kDisplayRenderMethod, &gopts.render_method),
VbamOption(VbamOptionID::kDisplayScale, &gopts.video_scale, 1, 6),
VbamOption(VbamOptionID::kDisplayStretch, &gopts.retain_aspect),
/// GB
VbamOption(VbamOptionID::kGBBiosFile, &gopts.gb_bios),
VbamOption(VbamOptionID::kGBColorOption, &gbColorOption, 0, 1),
VbamOption(VbamOptionID::kGBColorizerHack, &colorizerHack, 0, 1),
VbamOption(VbamOptionID::kGBLCDFilter, &gbLcdFilter),
VbamOption(VbamOptionID::kGBGBCBiosFile, &gopts.gbc_bios),
VbamOption(VbamOptionID::kGBPalette0, systemGbPalette),
VbamOption(VbamOptionID::kGBPalette1, systemGbPalette + 8),
VbamOption(VbamOptionID::kGBPalette2, systemGbPalette + 16),
VbamOption(VbamOptionID::kGBPrintAutoPage, &gopts.print_auto_page),
VbamOption(VbamOptionID::kGBPrintScreenCap, &gopts.print_screen_cap),
VbamOption(VbamOptionID::kGBROMDir, &gopts.gb_rom_dir),
VbamOption(VbamOptionID::kGBGBCROMDir, &gopts.gbc_rom_dir),
/// GBA
VbamOption(VbamOptionID::kGBABiosFile, &gopts.gba_bios),
VbamOption(VbamOptionID::kGBALCDFilter, &gbaLcdFilter),
#ifndef NO_LINK
VbamOption(VbamOptionID::kGBALinkAuto, &gopts.link_auto),
VbamOption(VbamOptionID::kGBALinkFast, &linkHacks, 0, 1),
VbamOption(VbamOptionID::kGBALinkHost, &gopts.link_host),
VbamOption(VbamOptionID::kGBAServerIP, &gopts.server_ip),
VbamOption(VbamOptionID::kGBALinkPort, &gopts.link_port, 0, 65535),
VbamOption(VbamOptionID::kGBALinkProto, &gopts.link_proto, 0, 1),
VbamOption(VbamOptionID::kGBALinkTimeout, &linkTimeout, 0, 9999999),
VbamOption(VbamOptionID::kGBALinkType, &gopts.gba_link_type, 0, 5),
#endif
VbamOption(VbamOptionID::kGBAROMDir, &gopts.gba_rom_dir),
/// General
VbamOption(VbamOptionID::kGeneralAutoLoadLastState, &gopts.autoload_state),
VbamOption(VbamOptionID::kGeneralBatteryDir, &gopts.battery_dir),
VbamOption(VbamOptionID::kGeneralFreezeRecent, &gopts.recent_freeze),
VbamOption(VbamOptionID::kGeneralRecordingDir, &gopts.recording_dir),
VbamOption(VbamOptionID::kGeneralRewindInterval, &gopts.rewind_interval, 0, 600),
VbamOption(VbamOptionID::kGeneralScreenshotDir, &gopts.scrshot_dir),
VbamOption(VbamOptionID::kGeneralStateDir, &gopts.state_dir),
VbamOption(VbamOptionID::kGeneralStatusBar, &gopts.statusbar, 0, 1),
/// Joypad
VbamOption(VbamOptionID::kJoypad),
VbamOption(VbamOptionID::kJoypadAutofireThrottle, &gopts.autofire_rate, 1, 1000),
VbamOption(VbamOptionID::kJoypadDefault, &gopts.default_stick, 1, 4),
/// Keyboard
VbamOption(VbamOptionID::kKeyboard),
// Core
VbamOption(VbamOptionID::kpreferencesagbPrint, &agbPrint, 0, 1),
VbamOption(VbamOptionID::kpreferencesautoFrameSkip, &autoFrameSkip, 0, 1),
VbamOption(VbamOptionID::kpreferencesautoPatch, &autoPatch, 0, 1),
VbamOption(VbamOptionID::kpreferencesautoSaveLoadCheatList, &gopts.autoload_cheats),
VbamOption(VbamOptionID::kpreferencesborderAutomatic, &gbBorderAutomatic, 0, 1),
VbamOption(VbamOptionID::kpreferencesborderOn, &gbBorderOn, 0, 1),
VbamOption(VbamOptionID::kpreferencescaptureFormat, &captureFormat, 0, 1),
VbamOption(VbamOptionID::kpreferencescheatsEnabled, &cheatsEnabled, 0, 1),
#ifdef MMX
VbamOption(VbamOptionID::kpreferencesenableMMX, &enableMMX, 0, 1),
#endif
VbamOption(VbamOptionID::kpreferencesdisableStatus, &disableStatusMessages, 0, 1),
VbamOption(VbamOptionID::kpreferencesemulatorType, &gbEmulatorType, 0, 5),
VbamOption(VbamOptionID::kpreferencesflashSize, &optFlashSize, 0, 1),
VbamOption(VbamOptionID::kpreferencesframeSkip, &frameSkip, -1, 9),
VbamOption(VbamOptionID::kpreferencesfsColorDepth, &fsColorDepth, 0, 999),
VbamOption(VbamOptionID::kpreferencesfsFrequency, &fsFrequency, 0, 999),
VbamOption(VbamOptionID::kpreferencesfsHeight, &fsHeight, 0, 99999),
VbamOption(VbamOptionID::kpreferencesfsWidth, &fsWidth, 0, 99999),
VbamOption(VbamOptionID::kpreferencesgbPaletteOption, &gbPaletteOption, 0, 2),
VbamOption(VbamOptionID::kpreferencesgbPrinter, &winGbPrinterEnabled, 0, 1),
VbamOption(VbamOptionID::kpreferencesgdbBreakOnLoad, &gdbBreakOnLoad, 0, 1),
VbamOption(VbamOptionID::kpreferencesgdbPort, &gdbPort, 0, 65535),
#ifndef NO_LINK
VbamOption(VbamOptionID::kpreferencesLinkNumPlayers, &linkNumPlayers, 2, 4),
#endif
VbamOption(VbamOptionID::kpreferencesmaxScale, &maxScale, 0, 100),
VbamOption(VbamOptionID::kpreferencespauseWhenInactive, &pauseWhenInactive, 0, 1),
VbamOption(VbamOptionID::kpreferencesrtcEnabled, &rtcEnabled, 0, 1),
VbamOption(VbamOptionID::kpreferencessaveType, &cpuSaveType, 0, 5),
VbamOption(VbamOptionID::kpreferencesshowSpeed, &showSpeed, 0, 2),
VbamOption(VbamOptionID::kpreferencesshowSpeedTransparent, &showSpeedTransparent, 0, 1),
VbamOption(VbamOptionID::kpreferencesskipBios, &skipBios, 0, 1),
VbamOption(VbamOptionID::kpreferencesskipSaveGameCheats, &skipSaveGameCheats, 0, 1),
VbamOption(VbamOptionID::kpreferencesskipSaveGameBattery, &skipSaveGameBattery, 0, 1),
VbamOption(VbamOptionID::kpreferencesthrottle, &throttle, 0, 450),
VbamOption(VbamOptionID::kpreferencesspeedupThrottle, &speedup_throttle, 0, 3000),
VbamOption(VbamOptionID::kpreferencesspeedupFrameSkip, &speedup_frame_skip, 0, 300),
VbamOption(VbamOptionID::kpreferencesspeedupThrottleFrameSkip, &speedup_throttle_frame_skip),
VbamOption(VbamOptionID::kpreferencesuseBiosGB, &useBiosFileGB, 0, 1),
VbamOption(VbamOptionID::kpreferencesuseBiosGBA, &useBiosFileGBA, 0, 1),
VbamOption(VbamOptionID::kpreferencesuseBiosGBC, &useBiosFileGBC, 0, 1),
VbamOption(VbamOptionID::kpreferencesvsync, &vsync, 0, 1),
/// Geometry
VbamOption(VbamOptionID::kgeometryfullScreen, &fullScreen, 0, 1),
VbamOption(VbamOptionID::kgeometryisMaximized, &windowMaximized, 0, 1),
VbamOption(VbamOptionID::kgeometrywindowHeight, &windowHeight, 0, 99999),
VbamOption(VbamOptionID::kgeometrywindowWidth, &windowWidth, 0, 99999),
VbamOption(VbamOptionID::kgeometrywindowX, &windowPositionX, -1, 99999),
VbamOption(VbamOptionID::kgeometrywindowY, &windowPositionY, -1, 99999),
/// UI
VbamOption(VbamOptionID::kuiallowKeyboardBackgroundInput, &allowKeyboardBackgroundInput),
VbamOption(VbamOptionID::kuiallowJoystickBackgroundInput, &allowJoystickBackgroundInput),
VbamOption(VbamOptionID::kuihideMenuBar, &gopts.hide_menu_bar),
/// Sound
VbamOption(VbamOptionID::kSoundAudioAPI, &gopts.audio_api),
VbamOption(VbamOptionID::kSoundAudioDevice, &gopts.audio_dev),
VbamOption(VbamOptionID::kSoundBuffers, &gopts.audio_buffers, 2, 10),
VbamOption(VbamOptionID::kSoundEnable, &gopts.sound_en, 0, 0x30f),
VbamOption(VbamOptionID::kSoundGBAFiltering, &gopts.gba_sound_filter, 0, 100),
VbamOption(VbamOptionID::kSoundGBAInterpolation, &gopts.soundInterpolation),
VbamOption(VbamOptionID::kSoundGBDeclicking, &gopts.gb_declick),
VbamOption(VbamOptionID::kSoundGBEcho, &gopts.gb_echo, 0, 100),
VbamOption(VbamOptionID::kSoundGBEnableEffects, &gopts.gb_effects_config_enabled),
VbamOption(VbamOptionID::kSoundGBStereo, &gopts.gb_stereo, 0, 100),
VbamOption(VbamOptionID::kSoundGBSurround, &gopts.gb_effects_config_surround),
VbamOption(VbamOptionID::kSoundQuality, &gopts.sound_qual),
VbamOption(VbamOptionID::kSoundVolume, &gopts.sound_vol, 0, 200),
};
return g_all_opts;
}
namespace internal {
// These MUST follow the same order as the definitions in VbamOptionID.
// Adding an option without adding to this array will result in a compiler
// error since kNbOptions is automatically updated.
const std::array<VbamOptionData, kNbOptions + 1> kAllOptionsData = {
/// Display
VbamOptionData { "Display/Bilinear", "Bilinear", _("Use bilinear filter with 3d renderer"), VbamOption::Type::kBool },
VbamOptionData { "Display/Filter", "", _("Full-screen filter to apply"), VbamOption::Type::kFilter },
VbamOptionData { "Display/FilterPlugin", "", _("Filter plugin library"), VbamOption::Type::kString },
VbamOptionData { "Display/IFB", "", _("Interframe blending function"), VbamOption::Type::kInterframe },
VbamOptionData { "Display/KeepOnTop", "KeepOnTop", _("Keep window on top"), VbamOption::Type::kBool },
VbamOptionData { "Display/MaxThreads", "Multithread", _("Maximum number of threads to run filters in"), VbamOption::Type::kInt },
VbamOptionData { "Display/RenderMethod", "", _("Render method; if unsupported, simple method will be used"), VbamOption::Type::kRenderMethod },
VbamOptionData { "Display/Scale", "", _("Default scale factor"), VbamOption::Type::kDouble },
VbamOptionData { "Display/Stretch", "RetainAspect", _("Retain aspect ratio when resizing"), VbamOption::Type::kBool },
/// GB
VbamOptionData { "GB/BiosFile", "", _("BIOS file to use for GB, if enabled"), VbamOption::Type::kString },
VbamOptionData { "GB/ColorOption", "GBColorOption", _("GB color enhancement, if enabled"), VbamOption::Type::kInt },
VbamOptionData { "GB/ColorizerHack", "ColorizerHack", _("Enable DX Colorization Hacks"), VbamOption::Type::kInt },
VbamOptionData { "GB/LCDFilter", "GBLcdFilter", _("Apply LCD filter, if enabled"), VbamOption::Type::kBool },
VbamOptionData { "GB/GBCBiosFile", "", _("BIOS file to use for GBC, if enabled"), VbamOption::Type::kString },
VbamOptionData { "GB/Palette0", "", _("The default palette, as 8 comma-separated 4-digit hex integers (rgb555)."), VbamOption::Type::kGbPalette },
VbamOptionData { "GB/Palette1", "", _("The first user palette, as 8 comma-separated 4-digit hex integers (rgb555)."), VbamOption::Type::kGbPalette },
VbamOptionData { "GB/Palette2", "", _("The second user palette, as 8 comma-separated 4-digit hex integers (rgb555)."), VbamOption::Type::kGbPalette },
VbamOptionData { "GB/PrintAutoPage", "PrintGather", _("Automatically gather a full page before printing"), VbamOption::Type::kBool },
VbamOptionData { "GB/PrintScreenCap", "PrintSnap", _("Automatically save printouts as screen captures with -print suffix"), VbamOption::Type::kBool },
VbamOptionData { "GB/ROMDir", "", _("Directory to look for ROM files"), VbamOption::Type::kString },
VbamOptionData { "GB/GBCROMDir", "", _("Directory to look for GBC ROM files"), VbamOption::Type::kString },
/// GBA
VbamOptionData { "GBA/BiosFile", "", _("BIOS file to use, if enabled"), VbamOption::Type::kString },
VbamOptionData { "GBA/LCDFilter", "GBALcdFilter", _("Apply LCD filter, if enabled"), VbamOption::Type::kBool },
#ifndef NO_LINK
VbamOptionData { "GBA/LinkAuto", "LinkAuto", _("Enable link at boot"), VbamOption::Type::kBool },
VbamOptionData { "GBA/LinkFast", "SpeedOn", _("Enable faster network protocol by default"), VbamOption::Type::kInt },
VbamOptionData { "GBA/LinkHost", "", _("Default network link client host"), VbamOption::Type::kString },
VbamOptionData { "GBA/ServerIP", "", _("Default network link server IP to bind"), VbamOption::Type::kString },
VbamOptionData { "GBA/LinkPort", "", _("Default network link port (server and client)"), VbamOption::Type::kUnsigned },
VbamOptionData { "GBA/LinkProto", "LinkProto", _("Default network protocol"), VbamOption::Type::kInt },
VbamOptionData { "GBA/LinkTimeout", "LinkTimeout", _("Link timeout (ms)"), VbamOption::Type::kInt },
VbamOptionData { "GBA/LinkType", "LinkType", _("Link cable type"), VbamOption::Type::kInt },
#endif
VbamOptionData { "GBA/ROMDir", "", _("Directory to look for ROM files"), VbamOption::Type::kString },
/// General
VbamOptionData { "General/AutoLoadLastState", "", _("Automatically load last saved state"), VbamOption::Type::kBool },
VbamOptionData { "General/BatteryDir", "", _("Directory to store game save files (relative paths are relative to ROM; blank is config dir)"), VbamOption::Type::kString },
VbamOptionData { "General/FreezeRecent", "", _("Freeze recent load list"), VbamOption::Type::kBool },
VbamOptionData { "General/RecordingDir", "", _("Directory to store A/V and game recordings (relative paths are relative to ROM)"), VbamOption::Type::kString },
VbamOptionData { "General/RewindInterval", "", _("Number of seconds between rewind snapshots (0 to disable)"), VbamOption::Type::kInt },
VbamOptionData { "General/ScreenshotDir", "", _("Directory to store screenshots (relative paths are relative to ROM)"), VbamOption::Type::kString },
VbamOptionData { "General/StateDir", "", _("Directory to store saved state files (relative paths are relative to BatteryDir)"), VbamOption::Type::kString },
VbamOptionData { "General/StatusBar", "StatusBar", _("Enable status bar"), VbamOption::Type::kInt },
/// Joypad
VbamOptionData { "Joypad/*/*", "", _("The parameter Joypad/<n>/<button> contains a comma-separated list of key names which map to joypad #<n> button <button>. Button is one of Up, Down, Left, Right, A, B, L, R, Select, Start, MotionUp, MotionDown, MotionLeft, MotionRight, AutoA, AutoB, Speed, Capture, GS"), VbamOption::Type::kNone },
VbamOptionData { "Joypad/AutofireThrottle", "", _("The autofire toggle period, in frames (1/60 s)"), VbamOption::Type::kInt },
VbamOptionData { "Joypad/Default", "", _("The number of the stick to use in single-player mode"), VbamOption::Type::kInt },
/// Keyboard
VbamOptionData { "Keyboard/*", "", _("The parameter Keyboard/<cmd> contains a comma-separated list of key names (e.g. Alt-Shift-F1). When the named key is pressed, the command <cmd> is executed."), VbamOption::Type::kNone },
// Core
VbamOptionData { "preferences/agbPrint", "AGBPrinter", _("Enable AGB debug print"), VbamOption::Type::kInt },
VbamOptionData { "preferences/autoFrameSkip", "FrameSkipAuto", _("Auto skip frames."), VbamOption::Type::kInt },
VbamOptionData { "preferences/autoPatch", "ApplyPatches", _("Apply IPS/UPS/IPF patches if found"), VbamOption::Type::kInt },
VbamOptionData { "preferences/autoSaveLoadCheatList", "", _("Automatically save and load cheat list"), VbamOption::Type::kBool },
VbamOptionData { "preferences/borderAutomatic", "", _("Automatically enable border for Super GameBoy games"), VbamOption::Type::kInt },
VbamOptionData { "preferences/borderOn", "", _("Always enable border"), VbamOption::Type::kInt },
VbamOptionData { "preferences/captureFormat", "", _("Screen capture file format"), VbamOption::Type::kInt },
VbamOptionData { "preferences/cheatsEnabled", "", _("Enable cheats"), VbamOption::Type::kInt },
#ifdef MMX
VbamOptionData { "preferences/enableMMX", "MMX", _("Enable MMX"), VbamOption::Type::kInt },
#endif
VbamOptionData { "preferences/disableStatus", "NoStatusMsg", _("Disable on-screen status messages"), VbamOption::Type::kInt },
VbamOptionData { "preferences/emulatorType", "", _("Type of system to emulate"), VbamOption::Type::kInt },
VbamOptionData { "preferences/flashSize", "", _("Flash size 0 = 64KB 1 = 128KB"), VbamOption::Type::kInt },
VbamOptionData { "preferences/frameSkip", "FrameSkip", _("Skip frames. Values are 0-9 or -1 to skip automatically based on time."), VbamOption::Type::kInt },
VbamOptionData { "preferences/fsColorDepth", "", _("Fullscreen mode color depth (0 = any)"), VbamOption::Type::kInt },
VbamOptionData { "preferences/fsFrequency", "", _("Fullscreen mode frequency (0 = any)"), VbamOption::Type::kInt },
VbamOptionData { "preferences/fsHeight", "", _("Fullscreen mode height (0 = desktop)"), VbamOption::Type::kInt },
VbamOptionData { "preferences/fsWidth", "", _("Fullscreen mode width (0 = desktop)"), VbamOption::Type::kInt },
VbamOptionData { "preferences/gbPaletteOption", "", _("The palette to use"), VbamOption::Type::kInt },
VbamOptionData { "preferences/gbPrinter", "Printer", _("Enable printer emulation"), VbamOption::Type::kInt },
VbamOptionData { "preferences/gdbBreakOnLoad", "DebugGDBBreakOnLoad", _("Break into GDB after loading the game."), VbamOption::Type::kInt },
VbamOptionData { "preferences/gdbPort", "DebugGDBPort", _("Port to connect GDB to."), VbamOption::Type::kInt },
#ifndef NO_LINK
VbamOptionData { "preferences/LinkNumPlayers", "", _("Number of players in network"), VbamOption::Type::kInt },
#endif
VbamOptionData { "preferences/maxScale", "", _("Maximum scale factor (0 = no limit)"), VbamOption::Type::kInt },
VbamOptionData { "preferences/pauseWhenInactive", "PauseWhenInactive", _("Pause game when main window loses focus"), VbamOption::Type::kInt },
VbamOptionData { "preferences/rtcEnabled", "RTC", _("Enable RTC (vba-over.ini override is rtcEnabled"), VbamOption::Type::kInt },
VbamOptionData { "preferences/saveType", "", _("Native save (\"battery\") hardware type"), VbamOption::Type::kInt },
VbamOptionData { "preferences/showSpeed", "", _("Show speed indicator"), VbamOption::Type::kInt },
VbamOptionData { "preferences/showSpeedTransparent", "Transparent", _("Draw on-screen messages transparently"), VbamOption::Type::kInt },
VbamOptionData { "preferences/skipBios", "SkipIntro", _("Skip BIOS initialization"), VbamOption::Type::kInt },
VbamOptionData { "preferences/skipSaveGameCheats", "", _("Do not overwrite cheat list when loading state"), VbamOption::Type::kInt },
VbamOptionData { "preferences/skipSaveGameBattery", "", _("Do not overwrite native (battery) save when loading state"), VbamOption::Type::kInt },
VbamOptionData { "preferences/throttle", "", _("Throttle game speed, even when accelerated (0-450%, 0 = no throttle)"), VbamOption::Type::kUnsigned },
VbamOptionData { "preferences/speedupThrottle", "", _("Set throttle for speedup key (0-3000%, 0 = no throttle)"), VbamOption::Type::kUnsigned },
VbamOptionData { "preferences/speedupFrameSkip", "", _("Number of frames to skip with speedup (instead of speedup throttle)"), VbamOption::Type::kUnsigned },
VbamOptionData { "preferences/speedupThrottleFrameSkip", "", _("Use frame skip for speedup throttle"), VbamOption::Type::kBool },
VbamOptionData { "preferences/useBiosGB", "BootRomGB", _("Use the specified BIOS file for GB"), VbamOption::Type::kInt },
VbamOptionData { "preferences/useBiosGBA", "BootRomEn", _("Use the specified BIOS file"), VbamOption::Type::kInt },
VbamOptionData { "preferences/useBiosGBC", "BootRomGBC", _("Use the specified BIOS file for GBC"), VbamOption::Type::kInt },
VbamOptionData { "preferences/vsync", "VSync", _("Wait for vertical sync"), VbamOption::Type::kInt },
/// Geometry
VbamOptionData { "geometry/fullScreen", "Fullscreen", _("Enter fullscreen mode at startup"), VbamOption::Type::kInt },
VbamOptionData { "geometry/isMaximized", "Maximized", _("Window maximized"), VbamOption::Type::kInt },
VbamOptionData { "geometry/windowHeight", "Height", _("Window height at startup"), VbamOption::Type::kUnsigned },
VbamOptionData { "geometry/windowWidth", "Width", _("Window width at startup"), VbamOption::Type::kUnsigned },
VbamOptionData { "geometry/windowX", "X", _("Window axis X position at startup"), VbamOption::Type::kInt },
VbamOptionData { "geometry/windowY", "Y", _("Window axis Y position at startup"), VbamOption::Type::kInt },
/// UI
VbamOptionData { "ui/allowKeyboardBackgroundInput", "AllowKeyboardBackgroundInput", _("Capture key events while on background"), VbamOption::Type::kBool },
VbamOptionData { "ui/allowJoystickBackgroundInput", "AllowJoystickBackgroundInput", _("Capture joy events while on background"), VbamOption::Type::kBool },
VbamOptionData { "ui/hideMenuBar", "", _("Hide menu bar when mouse is inactive"), VbamOption::Type::kBool },
/// Sound
VbamOptionData { "Sound/AudioAPI", "", _("Sound API; if unsupported, default API will be used"), VbamOption::Type::kAudioApi },
VbamOptionData { "Sound/AudioDevice", "", _("Device ID of chosen audio device for chosen driver"), VbamOption::Type::kString },
VbamOptionData { "Sound/Buffers", "", _("Number of sound buffers"), VbamOption::Type::kInt },
VbamOptionData { "Sound/Enable", "", _("Bit mask of sound channels to enable"), VbamOption::Type::kInt },
VbamOptionData { "Sound/GBAFiltering", "", _("GBA sound filtering (%)"), VbamOption::Type::kInt },
VbamOptionData { "Sound/GBAInterpolation", "GBASoundInterpolation", _("GBA sound interpolation"), VbamOption::Type::kBool },
VbamOptionData { "Sound/GBDeclicking", "GBDeclicking", _("GB sound declicking"), VbamOption::Type::kBool },
VbamOptionData { "Sound/GBEcho", "", _("GB echo effect (%)"), VbamOption::Type::kInt },
VbamOptionData { "Sound/GBEnableEffects", "GBEnhanceSound", _("Enable GB sound effects"), VbamOption::Type::kBool },
VbamOptionData { "Sound/GBStereo", "", _("GB stereo effect (%)"), VbamOption::Type::kInt },
VbamOptionData { "Sound/GBSurround", "GBSurround", _("GB surround sound effect (%)"), VbamOption::Type::kBool },
VbamOptionData { "Sound/Quality", "", _("Sound sample rate (kHz)"), VbamOption::Type::kSoundQuality },
VbamOptionData { "Sound/Volume", "", _("Sound volume (%)"), VbamOption::Type::kInt },
// Last
VbamOptionData { "", "", "", VbamOption::Type::kNone },
};
nonstd::optional<VbamOptionID> StringToOptionId(const wxString& input) {
// Note: This map does not include "Joystick" and "Keyboard". This is on
// purpose, as these are handled separately.
static const std::map<wxString, VbamOptionID> kStringToOptionId = {
{ "Display/Bilinear", VbamOptionID::kDisplayBilinear },
{ "Display/Filter", VbamOptionID::kDisplayFilter },
{ "Display/FilterPlugin", VbamOptionID::kDisplayFilterPlugin },
{ "Display/IFB", VbamOptionID::kDisplayIFB },
{ "Display/KeepOnTop", VbamOptionID::kDisplayKeepOnTop },
{ "Display/MaxThreads", VbamOptionID::kDisplayMaxThreads },
{ "Display/RenderMethod", VbamOptionID::kDisplayRenderMethod },
{ "Display/Scale", VbamOptionID::kDisplayScale },
{ "Display/Stretch", VbamOptionID::kDisplayStretch },
/// GB
{ "GB/BiosFile", VbamOptionID::kGBBiosFile },
{ "GB/ColorOption", VbamOptionID::kGBColorOption },
{ "GB/ColorizerHack", VbamOptionID::kGBColorizerHack },
{ "GB/LCDFilter", VbamOptionID::kGBLCDFilter },
{ "GB/GBCBiosFile", VbamOptionID::kGBGBCBiosFile },
{ "GB/Palette0", VbamOptionID::kGBPalette0 },
{ "GB/Palette1", VbamOptionID::kGBPalette1 },
{ "GB/Palette2", VbamOptionID::kGBPalette2 },
{ "GB/PrintAutoPage", VbamOptionID::kGBPrintAutoPage },
{ "GB/PrintScreenCap", VbamOptionID::kGBPrintScreenCap },
{ "GB/ROMDir", VbamOptionID::kGBROMDir },
{ "GB/GBCROMDir", VbamOptionID::kGBGBCROMDir },
/// GBA
{ "GBA/BiosFile", VbamOptionID::kGBABiosFile },
{ "GBA/LCDFilter", VbamOptionID::kGBALCDFilter },
#ifndef NO_LINK
{ "GBA/LinkAuto", VbamOptionID::kGBALinkAuto },
{ "GBA/LinkFast", VbamOptionID::kGBALinkFast },
{ "GBA/LinkHost", VbamOptionID::kGBALinkHost },
{ "GBA/ServerIP", VbamOptionID::kGBAServerIP },
{ "GBA/LinkPort", VbamOptionID::kGBALinkPort },
{ "GBA/LinkProto", VbamOptionID::kGBALinkProto },
{ "GBA/LinkTimeout", VbamOptionID::kGBALinkTimeout },
{ "GBA/LinkType", VbamOptionID::kGBALinkType },
#endif
{ "GBA/ROMDir", VbamOptionID::kGBAROMDir },
/// General
{ "General/AutoLoadLastState", VbamOptionID::kGeneralAutoLoadLastState },
{ "General/BatteryDir", VbamOptionID::kGeneralBatteryDir },
{ "General/FreezeRecent", VbamOptionID::kGeneralFreezeRecent },
{ "General/RecordingDir", VbamOptionID::kGeneralRecordingDir },
{ "General/RewindInterval", VbamOptionID::kGeneralRewindInterval },
{ "General/ScreenshotDir", VbamOptionID::kGeneralScreenshotDir },
{ "General/StateDir", VbamOptionID::kGeneralStateDir },
{ "General/StatusBar", VbamOptionID::kGeneralStatusBar },
/// Joypad
{ "Joypad/AutofireThrottle", VbamOptionID::kJoypadAutofireThrottle },
{ "Joypad/Default", VbamOptionID::kJoypadDefault },
// Core
{ "preferences/agbPrint", VbamOptionID::kpreferencesagbPrint },
{ "preferences/autoFrameSkip", VbamOptionID::kpreferencesautoFrameSkip },
{ "preferences/autoPatch", VbamOptionID::kpreferencesautoPatch },
{ "preferences/autoSaveLoadCheatList", VbamOptionID::kpreferencesautoSaveLoadCheatList },
{ "preferences/borderAutomatic", VbamOptionID::kpreferencesborderAutomatic },
{ "preferences/borderOn", VbamOptionID::kpreferencesborderOn },
{ "preferences/captureFormat", VbamOptionID::kpreferencescaptureFormat },
{ "preferences/cheatsEnabled", VbamOptionID::kpreferencescheatsEnabled },
#ifdef MMX
{ "preferences/enableMMX", VbamOptionID::kpreferencesenableMMX },
#endif
{ "preferences/disableStatus", VbamOptionID::kpreferencesdisableStatus },
{ "preferences/emulatorType", VbamOptionID::kpreferencesemulatorType },
{ "preferences/flashSize", VbamOptionID::kpreferencesflashSize },
{ "preferences/frameSkip", VbamOptionID::kpreferencesframeSkip },
{ "preferences/fsColorDepth", VbamOptionID::kpreferencesfsColorDepth },
{ "preferences/fsFrequency", VbamOptionID::kpreferencesfsFrequency },
{ "preferences/fsHeight", VbamOptionID::kpreferencesfsHeight },
{ "preferences/fsWidth", VbamOptionID::kpreferencesfsWidth },
{ "preferences/gbPaletteOption", VbamOptionID::kpreferencesgbPaletteOption },
{ "preferences/gbPrinter", VbamOptionID::kpreferencesgbPrinter },
{ "preferences/gdbBreakOnLoad", VbamOptionID::kpreferencesgdbBreakOnLoad },
{ "preferences/gdbPort", VbamOptionID::kpreferencesgdbPort },
#ifndef NO_LINK
{ "preferences/LinkNumPlayers", VbamOptionID::kpreferencesLinkNumPlayers },
#endif
{ "preferences/maxScale", VbamOptionID::kpreferencesmaxScale },
{ "preferences/pauseWhenInactive", VbamOptionID::kpreferencespauseWhenInactive },
{ "preferences/rtcEnabled", VbamOptionID::kpreferencesrtcEnabled },
{ "preferences/saveType", VbamOptionID::kpreferencessaveType },
{ "preferences/showSpeed", VbamOptionID::kpreferencesshowSpeed },
{ "preferences/showSpeedTransparent", VbamOptionID::kpreferencesshowSpeedTransparent },
{ "preferences/skipBios", VbamOptionID::kpreferencesskipBios },
{ "preferences/skipSaveGameCheats", VbamOptionID::kpreferencesskipSaveGameCheats },
{ "preferences/skipSaveGameBattery", VbamOptionID::kpreferencesskipSaveGameBattery },
{ "preferences/throttle", VbamOptionID::kpreferencesthrottle },
{ "preferences/speedupThrottle", VbamOptionID::kpreferencesspeedupThrottle },
{ "preferences/speedupFrameSkip", VbamOptionID::kpreferencesspeedupFrameSkip },
{ "preferences/speedupThrottleFrameSkip", VbamOptionID::kpreferencesspeedupThrottleFrameSkip },
{ "preferences/useBiosGB", VbamOptionID::kpreferencesuseBiosGB },
{ "preferences/useBiosGBA", VbamOptionID::kpreferencesuseBiosGBA },
{ "preferences/useBiosGBC", VbamOptionID::kpreferencesuseBiosGBC },
{ "preferences/vsync", VbamOptionID::kpreferencesvsync },
/// Geometry
{ "geometry/fullScreen", VbamOptionID::kgeometryfullScreen },
{ "geometry/isMaximized", VbamOptionID::kgeometryisMaximized },
{ "geometry/windowHeight", VbamOptionID::kgeometrywindowHeight },
{ "geometry/windowWidth", VbamOptionID::kgeometrywindowWidth },
{ "geometry/windowX", VbamOptionID::kgeometrywindowX },
{ "geometry/windowY", VbamOptionID::kgeometrywindowY },
/// UI
{ "ui/allowKeyboardBackgroundInput", VbamOptionID::kuiallowKeyboardBackgroundInput },
{ "ui/allowJoystickBackgroundInput", VbamOptionID::kuiallowJoystickBackgroundInput },
{ "ui/hideMenuBar", VbamOptionID::kuihideMenuBar },
/// Sound
{ "Sound/AudioAPI", VbamOptionID::kSoundAudioAPI },
{ "Sound/AudioDevice", VbamOptionID::kSoundAudioDevice },
{ "Sound/Buffers", VbamOptionID::kSoundBuffers },
{ "Sound/Enable", VbamOptionID::kSoundEnable },
{ "Sound/GBAFiltering", VbamOptionID::kSoundGBAFiltering },
{ "Sound/GBAInterpolation", VbamOptionID::kSoundGBAInterpolation },
{ "Sound/GBDeclicking", VbamOptionID::kSoundGBDeclicking },
{ "Sound/GBEcho", VbamOptionID::kSoundGBEcho },
{ "Sound/GBEnableEffects", VbamOptionID::kSoundGBEnableEffects },
{ "Sound/GBStereo", VbamOptionID::kSoundGBStereo },
{ "Sound/GBSurround", VbamOptionID::kSoundGBSurround },
{ "Sound/Quality", VbamOptionID::kSoundQuality },
{ "Sound/Volume", VbamOptionID::kSoundVolume },
};
const auto iter = kStringToOptionId.find(input);
if (iter == kStringToOptionId.end()) {
return nonstd::nullopt;
}
return iter->second;
}
wxString FilterToString(int value) {
assert(value >= 0 && static_cast<size_t>(value) < kNbFilterFunctions);
return kFilterStrings[value];
}
wxString InterframeToString(int value) {
assert(value >= 0 && static_cast<size_t>(value) < kNbInterframes);
return kInterframeStrings[value];
}
wxString RenderMethodToString(int value) {
assert(value >= 0 && static_cast<size_t>(value) < kNbRenderMethods);
return kRenderMethodStrings[value];
}
wxString AudioApiToString(int value) {
assert(value >= 0 && static_cast<size_t>(value) < kNbAudioApis);
return kAudioApiStrings[value];
}
wxString SoundQualityToString(int value) {
assert(value >= 0 && static_cast<size_t>(value) < kNbSoundQualities);
return kSoundQualityStrings[value];
}
int StringToFilter(const wxString& config_name, const wxString& input) {
static const std::map<wxString, FilterFunction> kStringToFilter = {
{ kFilterStrings[0], FilterFunction::kNone },
{ kFilterStrings[1], FilterFunction::k2xsai },
{ kFilterStrings[2], FilterFunction::kSuper2xsai },
{ kFilterStrings[3], FilterFunction::kSupereagle },
{ kFilterStrings[4], FilterFunction::kPixelate },
{ kFilterStrings[5], FilterFunction::kAdvmame },
{ kFilterStrings[6], FilterFunction::kBilinear },
{ kFilterStrings[7], FilterFunction::kBilinearplus },
{ kFilterStrings[8], FilterFunction::kScanlines },
{ kFilterStrings[9], FilterFunction::kTvmode },
{ kFilterStrings[10], FilterFunction::kHQ2x },
{ kFilterStrings[11], FilterFunction::kLQ2x },
{ kFilterStrings[12], FilterFunction::kSimple2x },
{ kFilterStrings[13], FilterFunction::kSimple3x },
{ kFilterStrings[14], FilterFunction::kHQ3x },
{ kFilterStrings[15], FilterFunction::kSimple4x },
{ kFilterStrings[16], FilterFunction::kHQ4x },
{ kFilterStrings[17], FilterFunction::kXbrz2x },
{ kFilterStrings[18], FilterFunction::kXbrz3x },
{ kFilterStrings[19], FilterFunction::kXbrz4x },
{ kFilterStrings[20], FilterFunction::kXbrz5x },
{ kFilterStrings[21], FilterFunction::kXbrz6x },
{ kFilterStrings[22], FilterFunction::kPlugin },
};
assert(kFilterStrings.size() == kNbFilterFunctions);
const auto iter = kStringToFilter.find(input);
if (iter == kStringToFilter.end()) {
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
input,
config_name,
AllEnumValuesForType(VbamOption::Type::kFilter));
return 0;
}
return static_cast<int>(iter->second);
}
int StringToInterframe(const wxString& config_name, const wxString& input) {
static const std::map<wxString, Interframe> kStringToInterframe = {
{ kInterframeStrings[0], Interframe::kNone },
{ kInterframeStrings[1], Interframe::kSmart },
{ kInterframeStrings[2], Interframe::kMotionBlur },
};
assert(kStringToInterframe.size() == kNbInterframes);
const auto iter = kStringToInterframe.find(input);
if (iter == kStringToInterframe.end()) {
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
input,
config_name,
AllEnumValuesForType(VbamOption::Type::kInterframe));
return 0;
}
return static_cast<int>(iter->second);
}
int StringToRenderMethod(const wxString& config_name, const wxString& input) {
static const std::map<wxString, RenderMethod> kStringToRenderMethod = {
{ kRenderMethodStrings[0], RenderMethod::kSimple },
{ kRenderMethodStrings[1], RenderMethod::kOpenGL },
#ifdef __WXMSW__
{ kRenderMethodStrings[2], RenderMethod::kDirect3d },
#elif defined(__WXMAC__)
{ kRenderMethodStrings[2], RenderMethod::kQuartz2d },
#endif
};
assert(kStringToRenderMethod.size() == kNbRenderMethods);
const auto iter = kStringToRenderMethod.find(input);
if (iter == kStringToRenderMethod.end()) {
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
input,
config_name,
AllEnumValuesForType(VbamOption::Type::kRenderMethod));
return 0;
}
return static_cast<int>(iter->second);
}
int StringToAudioApi(const wxString& config_name, const wxString& input) {
static const std::map<wxString, AudioApi> kStringToAudioApi = {
{ kAudioApiStrings[0], AudioApi::kSdl },
{ kAudioApiStrings[1], AudioApi::kOpenAL },
{ kAudioApiStrings[2], AudioApi::kDirectSound },
{ kAudioApiStrings[3], AudioApi::kXAudio2 },
{ kAudioApiStrings[4], AudioApi::kFaudio },
};
assert(kStringToAudioApi.size() == kNbAudioApis);
const auto iter = kStringToAudioApi.find(input);
if (iter == kStringToAudioApi.end()) {
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
input,
config_name,
AllEnumValuesForType(VbamOption::Type::kAudioApi));
return 0;
}
return static_cast<int>(iter->second);
}
int StringToSoundQuality(const wxString& config_name, const wxString& input) {
static const std::map<wxString, SoundQuality> kStringToSoundQuality = {
{ kSoundQualityStrings[0], SoundQuality::k48kHz },
{ kSoundQualityStrings[1], SoundQuality::k44kHz },
{ kSoundQualityStrings[2], SoundQuality::k22kHz },
{ kSoundQualityStrings[3], SoundQuality::k11kHz },
};
assert(kStringToSoundQuality.size() == kNbSoundQualities);
const auto iter = kStringToSoundQuality.find(input);
if (iter == kStringToSoundQuality.end()) {
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
input,
config_name,
AllEnumValuesForType(VbamOption::Type::kSoundQuality));
return 0;
}
return static_cast<int>(iter->second);
}
wxString AllEnumValuesForType(VbamOption::Type type) {
switch (type) {
case VbamOption::Type::kFilter: {
static const wxString kAllFilterValues = AllEnumValuesForArray(kFilterStrings);
return kAllFilterValues;
}
case VbamOption::Type::kInterframe: {
static const wxString kAllInterframeValues = AllEnumValuesForArray(kInterframeStrings);
return kAllInterframeValues;
}
case VbamOption::Type::kRenderMethod: {
static const wxString kAllRenderValues = AllEnumValuesForArray(kRenderMethodStrings);
return kAllRenderValues;
}
case VbamOption::Type::kAudioApi: {
static const wxString kAllAudioApiValues = AllEnumValuesForArray(kAudioApiStrings);
return kAllAudioApiValues;
}
case VbamOption::Type::kSoundQuality: {
static const wxString kAllSoundQualityValues = AllEnumValuesForArray(kSoundQualityStrings);
return kAllSoundQualityValues;
}
// We don't use default here to explicitly trigger a compiler warning when
// adding a new value.
case VbamOption::Type::kNone:
case VbamOption::Type::kBool:
case VbamOption::Type::kDouble:
case VbamOption::Type::kInt:
case VbamOption::Type::kUnsigned:
case VbamOption::Type::kString:
case VbamOption::Type::kGbPalette:
assert(false);
return wxEmptyString;
}
assert(false);
return wxEmptyString;
}
int MaxForType(VbamOption::Type type) {
switch (type) {
case VbamOption::Type::kFilter:
return kNbFilterFunctions;
case VbamOption::Type::kInterframe:
return kNbInterframes;
case VbamOption::Type::kRenderMethod:
return kNbRenderMethods;
case VbamOption::Type::kAudioApi:
return kNbAudioApis;
case VbamOption::Type::kSoundQuality:
return kNbSoundQualities;
// We don't use default here to explicitly trigger a compiler warning when
// adding a new value.
case VbamOption::Type::kNone:
case VbamOption::Type::kBool:
case VbamOption::Type::kDouble:
case VbamOption::Type::kInt:
case VbamOption::Type::kUnsigned:
case VbamOption::Type::kString:
case VbamOption::Type::kGbPalette:
assert(false);
return 0;
}
assert(false);
return 0;
}
} // namespace internal

368
src/wx/vbam-options.cpp Normal file
View File

@ -0,0 +1,368 @@
#include "vbam-options.h"
#include <variant>
#include <wx/log.h>
#include <wx/translation.h>
#define VBAM_OPTIONS_INTERNAL_INCLUDE
#include "vbam-options-internal.h"
#undef VBAM_OPTIONS_INTERNAL_INCLUDE
// static
VbamOption const* VbamOption::FindOptionByName(const wxString &config_name) {
nonstd::optional<VbamOptionID> option_id = internal::StringToOptionId(config_name);
if (!option_id) {
return nullptr;
}
return &FindOptionByID(option_id.value());
}
// static
VbamOption& VbamOption::FindOptionByID(VbamOptionID id) {
assert (id != VbamOptionID::Last);
return AllOptions()[static_cast<size_t>(id)];
}
VbamOption::~VbamOption() = default;
VbamOption::VbamOption(VbamOptionID id) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(),
min_(),
max_() {
assert(id != VbamOptionID::Last);
assert(is_none());
}
VbamOption::VbamOption(VbamOptionID id, bool* option) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(),
max_() {
assert(id != VbamOptionID::Last);
assert(is_bool());
}
VbamOption::VbamOption(VbamOptionID id, double* option, double min, double max) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(min),
max_(max) {
assert(id != VbamOptionID::Last);
assert(is_double());
// Validate the initial value.
SetDouble(*option);
}
VbamOption::VbamOption(VbamOptionID id, int32_t* option, int32_t min, int32_t max) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(min),
max_(max) {
assert(id != VbamOptionID::Last);
assert(is_int());
// Validate the initial value.
SetInt(*option);
}
VbamOption::VbamOption(VbamOptionID id, uint32_t* option, uint32_t min, uint32_t max) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(min),
max_(max) {
assert(id != VbamOptionID::Last);
assert(is_unsigned());
// Validate the initial value.
SetUnsigned(*option);
}
VbamOption::VbamOption(VbamOptionID id, wxString* option) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(),
max_() {
assert(id != VbamOptionID::Last);
assert(is_string());
}
VbamOption::VbamOption(VbamOptionID id, int* option) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(0),
max_(internal::MaxForType(type_)) {
assert(id != VbamOptionID::Last);
assert(is_filter() || is_interframe() || is_render_method() || is_audio_api() || is_sound_quality());
// Validate the initial value.
SetEnumInt(*option);
}
VbamOption::VbamOption(VbamOptionID id, uint16_t* option) :
id_(id),
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
value_(option),
min_(),
max_() {
assert(id != VbamOptionID::Last);
assert(is_gb_palette());
}
bool VbamOption::GetBool() const {
assert(is_bool());
return *(std::get<bool*>(value_));
}
double VbamOption::GetDouble() const {
assert(is_double());
return *(std::get<double*>(value_));
}
int32_t VbamOption::GetInt() const {
assert(is_int());
return *(std::get<int32_t*>(value_));
}
uint32_t VbamOption::GetUnsigned() const {
assert(is_unsigned());
return *(std::get<uint32_t*>(value_));
}
const wxString VbamOption::GetString() const {
assert(is_string());
return *(std::get<wxString*>(value_));
}
wxString VbamOption::GetEnumString() const {
switch (type_) {
case VbamOption::Type::kFilter:
return internal::FilterToString(*(std::get<int32_t*>(value_)));
case VbamOption::Type::kInterframe:
return internal::InterframeToString(*(std::get<int32_t*>(value_)));
case VbamOption::Type::kRenderMethod:
return internal::RenderMethodToString(*(std::get<int32_t*>(value_)));
case VbamOption::Type::kAudioApi:
return internal::AudioApiToString(*(std::get<int32_t*>(value_)));
case VbamOption::Type::kSoundQuality:
return internal::SoundQualityToString(*(std::get<int32_t*>(value_)));
// We don't use default here to explicitly trigger a compiler warning when
// adding a new value.
case VbamOption::Type::kNone:
case VbamOption::Type::kBool:
case VbamOption::Type::kDouble:
case VbamOption::Type::kInt:
case VbamOption::Type::kUnsigned:
case VbamOption::Type::kString:
case VbamOption::Type::kGbPalette:
assert(false);
return wxEmptyString;
}
assert(false);
return wxEmptyString;
}
wxString VbamOption::GetGbPaletteString() const {
assert(is_gb_palette());
wxString palette_string;
uint16_t const* value = std::get<uint16_t*>(value_);
palette_string.Printf("%04X,%04X,%04X,%04X,%04X,%04X,%04X,%04X",
value[0], value[1], value[2], value[3],
value[4], value[5], value[6], value[7]);
return palette_string;
}
void VbamOption::SetBool(bool value) const {
assert(is_bool());
*std::get<bool*>(value_) = value;
}
void VbamOption::SetDouble(double value) const {
assert(is_double());
if (value < std::get<double>(min_) || value > std::get<double>(max_)) {
wxLogWarning(
_("Invalid value %f for option %s; valid values are %f - %f"),
value,
config_name_,
std::get<double>(min_),
std::get<double>(max_));
return;
}
*std::get<double*>(value_) = value;
}
void VbamOption::SetInt(int32_t value) const {
assert(is_int());
if (value < std::get<int32_t>(min_) || value > std::get<int32_t>(max_)) {
wxLogWarning(
_("Invalid value %d for option %s; valid values are %d - %d"),
value,
config_name_,
std::get<int32_t>(min_),
std::get<int32_t>(max_));
return;
}
*std::get<int32_t*>(value_) = value;
}
void VbamOption::SetUnsigned(uint32_t value) const {
assert(is_unsigned());
if (value < std::get<uint32_t>(min_) || value > std::get<uint32_t>(max_)) {
wxLogWarning(
_("Invalid value %d for option %s; valid values are %d - %d"),
value,
config_name_,
std::get<uint32_t>(min_),
std::get<uint32_t>(max_));
return;
}
*std::get<uint32_t*>(value_) = value;
}
void VbamOption::SetString(const wxString& value) const {
assert(is_string());
*std::get<wxString*>(value_) = value;
}
void VbamOption::SetEnumString(const wxString& value) const {
switch (type_) {
case VbamOption::Type::kFilter:
SetEnumInt(internal::StringToFilter(config_name_, value));
return;
case VbamOption::Type::kInterframe:
SetEnumInt(internal::StringToInterframe(config_name_, value));
return;
case VbamOption::Type::kRenderMethod:
SetEnumInt(internal::StringToRenderMethod(config_name_, value));
return;
case VbamOption::Type::kAudioApi:
SetEnumInt(internal::StringToAudioApi(config_name_, value));
return;
case VbamOption::Type::kSoundQuality:
SetEnumInt(internal::StringToSoundQuality(config_name_, value));
return;
// We don't use default here to explicitly trigger a compiler warning when
// adding a new value.
case VbamOption::Type::kNone:
case VbamOption::Type::kBool:
case VbamOption::Type::kDouble:
case VbamOption::Type::kInt:
case VbamOption::Type::kUnsigned:
case VbamOption::Type::kString:
case VbamOption::Type::kGbPalette:
assert(false);
return;
}
}
void VbamOption::SetEnumInt(int value) const {
assert(is_filter() || is_interframe() || is_render_method() || is_audio_api() || is_sound_quality());
if (value < std::get<int32_t>(min_) || value > std::get<int32_t>(max_)) {
wxLogWarning(
_("Invalid value %d for option %s; valid values are %s"),
value,
config_name_,
internal::AllEnumValuesForType(type_));
return;
}
*std::get<int32_t*>(value_) = value;
}
void VbamOption::SetGbPalette(const wxString& value) const {
assert(is_gb_palette());
// 8 values of 4 chars and 7 commas.
static constexpr size_t kPaletteStringSize = 8 * 4 + 7;
if (value.size() != kPaletteStringSize) {
wxLogWarning(_("Invalid value %s for option %s"),
value,
config_name_);
return;
}
uint16_t* dest = std::get<uint16_t*>(value_);
for (size_t i = 0; i < 8; i++) {
wxString number = value.substr(i * 4, 4);
long temp = 0;
if (number.ToLong(&temp, 16)) {
dest[i] = temp;
}
}
}
wxString VbamOption::ToHelperString() const {
wxString helper_string = config_name_;
switch (type_) {
case VbamOption::Type::kNone:
break;
case VbamOption::Type::kBool:
helper_string.Append(" (flag)");
break;
case VbamOption::Type::kDouble:
helper_string.Append(" (decimal)");
break;
case VbamOption::Type::kInt:
helper_string.Append(" (int)");
break;
case VbamOption::Type::kUnsigned:
helper_string.Append(" (unsigned)");
break;
case VbamOption::Type::kString:
helper_string.Append(" (string)");
break;
case VbamOption::Type::kFilter:
case VbamOption::Type::kInterframe:
case VbamOption::Type::kRenderMethod:
case VbamOption::Type::kAudioApi:
case VbamOption::Type::kSoundQuality:
helper_string.Append(" (");
helper_string.Append(internal::AllEnumValuesForType(type_));
helper_string.Append(")");
break;
case VbamOption::Type::kGbPalette:
helper_string.Append(" (XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX)");
break;
}
helper_string.Append("\n\t");
helper_string.Append(ux_helper_);
helper_string.Append("\n");
return helper_string;
}

272
src/wx/vbam-options.h Normal file
View File

@ -0,0 +1,272 @@
#ifndef VBAM_OPTIONS_H
#define VBAM_OPTIONS_H
#include <array>
#include <variant>
#include <wx/string.h>
enum class VbamOptionID {
// Display
kDisplayBilinear = 0,
kDisplayFilter,
kDisplayFilterPlugin,
kDisplayIFB,
kDisplayKeepOnTop,
kDisplayMaxThreads,
kDisplayRenderMethod,
kDisplayScale,
kDisplayStretch,
/// GB
kGBBiosFile,
kGBColorOption,
kGBColorizerHack,
kGBLCDFilter,
kGBGBCBiosFile,
kGBPalette0,
kGBPalette1,
kGBPalette2,
kGBPrintAutoPage,
kGBPrintScreenCap,
kGBROMDir,
kGBGBCROMDir,
/// GBA
kGBABiosFile,
kGBALCDFilter,
#ifndef NO_LINK
kGBALinkAuto,
kGBALinkFast,
kGBALinkHost,
kGBAServerIP,
kGBALinkPort,
kGBALinkProto,
kGBALinkTimeout,
kGBALinkType,
#endif
kGBAROMDir,
/// General
kGeneralAutoLoadLastState,
kGeneralBatteryDir,
kGeneralFreezeRecent,
kGeneralRecordingDir,
kGeneralRewindInterval,
kGeneralScreenshotDir,
kGeneralStateDir,
kGeneralStatusBar,
/// Joypad
kJoypad,
kJoypadAutofireThrottle,
/// Keyboard
kJoypadDefault,
/// Keyboard
kKeyboard,
// Core
kpreferencesagbPrint,
kpreferencesautoFrameSkip,
kpreferencesautoPatch,
kpreferencesautoSaveLoadCheatList,
kpreferencesborderAutomatic,
kpreferencesborderOn,
kpreferencescaptureFormat,
kpreferencescheatsEnabled,
#ifdef MMX
kpreferencesenableMMX,
#endif
kpreferencesdisableStatus,
kpreferencesemulatorType,
kpreferencesflashSize,
kpreferencesframeSkip,
kpreferencesfsColorDepth,
kpreferencesfsFrequency,
kpreferencesfsHeight,
kpreferencesfsWidth,
kpreferencesgbPaletteOption,
kpreferencesgbPrinter,
kpreferencesgdbBreakOnLoad,
kpreferencesgdbPort,
#ifndef NO_LINK
kpreferencesLinkNumPlayers,
#endif
kpreferencesmaxScale,
kpreferencespauseWhenInactive,
kpreferencesrtcEnabled,
kpreferencessaveType,
kpreferencesshowSpeed,
kpreferencesshowSpeedTransparent,
kpreferencesskipBios,
kpreferencesskipSaveGameCheats,
kpreferencesskipSaveGameBattery,
kpreferencesthrottle,
kpreferencesspeedupThrottle,
kpreferencesspeedupFrameSkip,
kpreferencesspeedupThrottleFrameSkip,
kpreferencesuseBiosGB,
kpreferencesuseBiosGBA,
kpreferencesuseBiosGBC,
kpreferencesvsync,
/// Geometry
kgeometryfullScreen,
kgeometryisMaximized,
kgeometrywindowHeight,
kgeometrywindowWidth,
kgeometrywindowX,
kgeometrywindowY,
/// UI
kuiallowKeyboardBackgroundInput,
kuiallowJoystickBackgroundInput,
kuihideMenuBar,
/// Sound
kSoundAudioAPI,
kSoundAudioDevice,
kSoundBuffers,
kSoundEnable,
kSoundGBAFiltering,
kSoundGBAInterpolation,
kSoundGBDeclicking,
kSoundGBEcho,
kSoundGBEnableEffects,
kSoundGBStereo,
kSoundGBSurround,
kSoundQuality,
kSoundVolume,
// Do not add anything under here.
Last,
};
constexpr size_t kNbOptions = static_cast<size_t>(VbamOptionID::Last);
// Represents a single option saved in the INI file. VbamOption does not own the
// individual option, but keeps a pointer to where the data is actually saved.
//
// Ideally, options in the UI code should only be accessed and set via this
// class, which should also take care of updating the INI file when
// VbamOption::Set*() is called. This should also handle keyboard and joystick
// configuration so option parsing can be done in a uniform manner. If we ever
// get to that point, we would be able to remove most update_opts() calls and
// have individual UI elements access the option via
// VbamOption::FindOptionByID().
//
// The implementation for this class is largely inspired by base::Value in
// Chromium.
// https://source.chromium.org/chromium/chromium/src/+/main:base/values.h
class VbamOption {
public:
enum class Type {
kNone = 0,
kBool,
kDouble,
kInt,
kUnsigned,
kString,
kFilter,
kInterframe,
kRenderMethod,
kAudioApi,
kSoundQuality,
kGbPalette,
};
static std::array<VbamOption, kNbOptions>& AllOptions();
// O(log(kNbOptions))
static VbamOption const* FindOptionByName(const wxString& config_name);
// O(1)
static VbamOption& FindOptionByID(VbamOptionID id);
~VbamOption();
// Accessors.
const wxString& config_name() const { return config_name_; }
const wxString& command() const { return command_; }
const wxString& ux_helper() const { return ux_helper_; }
// Returns the type of the value stored by the current object.
Type type() const { return type_; }
// Returns true if the current object represents a given type.
bool is_none() const { return type() == Type::kNone; }
bool is_bool() const { return type() == Type::kBool; }
bool is_double() const { return type() == Type::kDouble; }
bool is_int() const { return type() == Type::kInt; }
bool is_unsigned() const { return type() == Type::kUnsigned; }
bool is_string() const { return type() == Type::kString; }
bool is_filter() const { return type() == Type::kFilter; }
bool is_interframe() const { return type() == Type::kInterframe; }
bool is_render_method() const { return type() == Type::kRenderMethod; }
bool is_audio_api() const { return type() == Type::kAudioApi; }
bool is_sound_quality() const { return type() == Type::kSoundQuality; }
bool is_gb_palette() const { return type() == Type::kGbPalette; }
// Returns a reference to the stored data. Will assert on type mismatch.
// All enum types go through GetEnumString().
bool GetBool() const;
double GetDouble() const;
int32_t GetInt() const;
uint32_t GetUnsigned() const;
const wxString GetString() const;
wxString GetEnumString() const;
wxString GetGbPaletteString() const;
// Sets the value. Will assert on type mismatch.
// All enum types go through SetEnumString() and SetEnumInt().
void SetBool(bool value) const;
void SetDouble(double value) const;
void SetInt(int32_t value) const;
void SetUnsigned(uint32_t value) const;
void SetString(const wxString& value) const;
void SetEnumString(const wxString& value) const;
void SetEnumInt(int value) const;
void SetGbPalette(const wxString& value) const;
// Command-line helper string.
wxString ToHelperString() const;
private:
// Disable copy and assignment. Every individual option is unique.
VbamOption(const VbamOption&) = delete;
VbamOption& operator=(const VbamOption&) = delete;
VbamOption(VbamOptionID id);
VbamOption(VbamOptionID id, bool* option);
VbamOption(VbamOptionID id, double* option, double min, double max);
VbamOption(VbamOptionID id, int32_t* option, int32_t min, int32_t max);
VbamOption(VbamOptionID id, uint32_t* option, uint32_t min, uint32_t max);
VbamOption(VbamOptionID id, wxString* option);
VbamOption(VbamOptionID id, int* option);
VbamOption(VbamOptionID id, uint16_t* option);
const VbamOptionID id_;
const wxString config_name_;
const wxString command_;
const wxString ux_helper_;
const Type type_;
const std::variant<
std::monostate,
bool*,
double*,
int32_t*,
uint32_t*,
wxString*,
uint16_t*>
value_;
const std::variant<std::monostate, double, int32_t, uint32_t> min_;
const std::variant<std::monostate, double, int32_t, uint32_t> max_;
};
#endif /* VBAM_OPTIONS_H */

View File

@ -4,6 +4,7 @@
// create & display main frame
#include "wxvbam.h"
#include <stdio.h>
#include <wx/cmdline.h>
#include <wx/file.h>
@ -19,14 +20,15 @@
#include <wx/url.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include "wayland.h"
#include "strutils.h"
// The built-in xrc file
#include "builtin-xrc.h"
// The built-in vba-over.ini
#include "builtin-over.h"
#include "strutils.h"
#include "vbam-options.h"
#include "wayland.h"
#include "wx/gamecontrol.h"
#include "wx/userinput.h"
@ -627,29 +629,19 @@ bool wxvbamApp::OnCmdLineParsed(wxCmdLineParser& cl)
}
if (cl.Found(wxT("o"))) {
// This was most likely done on a command line, so use
// stderr instead of gui for messages
wxLog::SetActiveTarget(new wxLogStderr);
wxPrintf(_("Options set from the command line are saved if any"
" configuration changes are made in the user interface.\n\n"
"For flag options, true and false are specified as 1 and 0, respectively.\n\n"));
for (int i = 0; i < num_opts; i++) {
wxPrintf(wxT("%s (%s"), opts[i].opt.c_str(),
opts[i].boolopt ? wxT("flag") : opts[i].stropt ? wxT("string") : !opts[i].enumvals.empty() ? opts[i].enumvals.c_str() : (opts[i].intopt ? wxT("int") : opts[i].doubleopt ? wxT("decimal") : wxT("string")));
if (!opts[i].enumvals.empty()) {
const wxString evx = wxGetTranslation(opts[i].enumvals);
if (wxStrcmp(evx, opts[i].enumvals))
wxPrintf(wxT(" = %s"), evx.c_str());
}
wxPrintf(wxT(")\n\t%s\n\n"), opts[i].desc.c_str());
if (!opts[i].enumvals.empty())
opts[i].enumvals = wxGetTranslation(opts[i].enumvals);
for (const VbamOption& opt : VbamOption::AllOptions()) {
wxPrintf("%s\n", opt.ToHelperString());
}
wxPrintf(_("The commands available for the Keyboard/* option are:\n\n"));
for (int i = 0; i < ncmds; i++)
wxPrintf(wxT("%s (%s)\n"), cmdtab[i].cmd.c_str(), cmdtab[i].name.c_str());

View File

@ -194,8 +194,8 @@ enum { CMDEN_GB = (1 << 0), // GB ROM loaded
struct checkable_mi_t {
int cmd;
wxMenuItem* mi;
bool* boolopt;
int *intopt, mask, val;
int mask, val;
bool initialized = false;
};
// wxArray is only for small types
@ -218,12 +218,12 @@ public:
~MainFrame();
bool BindControls();
void MenuOptionIntMask(const char* menuName, int& field, int mask);
void MenuOptionIntRadioValue(const char* menuName, int& field, int mask);
void MenuOptionBool(const char* menuName, bool& field);
void GetMenuOptionInt(const char* menuName, int& field, int mask);
void GetMenuOptionBool(const char* menuName, bool& field);
void SetMenuOption(const char* menuName, int value);
void MenuOptionIntMask(const wxString& menuName, int field, int mask);
void MenuOptionIntRadioValue(const wxString& menuName, int field, int mask);
void MenuOptionBool(const wxString& menuName, bool field);
void GetMenuOptionInt(const wxString& menuName, int field, int mask);
void GetMenuOptionBool(const wxString& menuName, bool field);
void SetMenuOption(const wxString& menuName, int value);
void SetJoystick();
@ -434,6 +434,7 @@ enum showspeed {
SS_DETAILED
};
// This enum must be kept in sync with the one in vbam-options-static.cpp.
enum filtfunc {
// this order must match order of option enum and selector widget
FF_NONE,
@ -469,14 +470,14 @@ enum filtfunc {
? 3 \
: x == FF_PLUGIN ? 0 : x == FF_NONE ? 1 : 2)
// This enum must be kept in sync with the one in vbam-options-static.cpp.
enum ifbfunc {
// this order must match order of option enum and selector widget
IFB_NONE,
IFB_SMART,
IFB_MOTION_BLUR
};
// make sure and keep this in sync with opts.cpp!
// This enum must be kept in sync with the one in vbam-options-static.cpp.
enum renderer {
RND_SIMPLE,
RND_OPENGL,
@ -484,7 +485,7 @@ enum renderer {
RND_QUARTZ2D,
};
// likewise
// This enum must be kept in sync with the one in vbam-options-static.cpp.
enum audioapi { AUD_SDL,
AUD_OPENAL,
AUD_DIRECTSOUND,