Move GameBoyConfig dialog to its own class
This changes all of the options handled by the GameBoyConfig dialog to use the new Option type. This also fixes a number of small issues related to palette handling and GB emulation: * Modifying the custom GB palette no longer incorrectly applies to GBC and SGB modes. * Loading a GB save state (not GBC or SGB) properly applies the user-defined palettte and not the one in the save state. * The GBC core now accepts .gbc BIOS files. Finally, this modifies and renames wxFarRadio to widgets::GroupCheckBox. In addition GroupCheckBoxes can now be loaded and fully configured from the XRC file rather than having to be manually configured on dialog initialization.
This commit is contained in:
parent
1d7e8ae4ed
commit
9889ef4fa8
File diff suppressed because it is too large
Load Diff
196
src/gb/GB.cpp
196
src/gb/GB.cpp
|
@ -1,17 +1,17 @@
|
|||
//#include "../win32/stdafx.h" // would fix LNK2005 linker errors for MSVC
|
||||
#include "gb.h"
|
||||
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <assert.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "../NLS.h"
|
||||
#include "../System.h"
|
||||
#include "../Util.h"
|
||||
#include "../gba/GBALink.h"
|
||||
#include "../gba/Sound.h"
|
||||
#include "gb.h"
|
||||
#include "gbCheats.h"
|
||||
#include "gbGlobals.h"
|
||||
#include "gbMemory.h"
|
||||
|
@ -22,6 +22,45 @@
|
|||
#define _stricmp strcasecmp
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// These are the default palettes when launching a GB game for GBC, GBA and
|
||||
// GBA SP, respectively.
|
||||
static constexpr std::array<uint16_t, 0x40> kGbGbcPalette = {
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x0600, 0xfdf3, 0x041c, 0xf5db, 0x4419, 0x57ea, 0x2808, 0x9b75,
|
||||
0x129b, 0xfce0, 0x22da, 0x4ac5, 0x2d71, 0xf0c2, 0x5137, 0x2d41,
|
||||
0x6b2d, 0x2215, 0xbe0a, 0xc053, 0xfe5f, 0xe000, 0xbe10, 0x914d,
|
||||
0x7f91, 0x02b5, 0x77ac, 0x14e5, 0xcf89, 0xa03d, 0xfd50, 0x91ff,
|
||||
};
|
||||
|
||||
static constexpr std::array<uint16_t, 0x40> kGbGbaPalette = {
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0xbe00, 0xfdfd, 0xbd69, 0x7baf, 0xf5ff, 0x3f8f, 0xcee5, 0x5bf7,
|
||||
0xb35b, 0xef97, 0xef9f, 0x97f7, 0x82bf, 0x9f3d, 0xddde, 0xbad5,
|
||||
0x3cba, 0xdfd7, 0xedea, 0xfeda, 0xf7f9, 0xfdee, 0x6d2f, 0xf0e6,
|
||||
0xf7f0, 0xf296, 0x3bf1, 0xe211, 0x69ba, 0x3d0d, 0xdfd3, 0xa6ba,
|
||||
};
|
||||
|
||||
static constexpr std::array<uint16_t, 0x40> kGbGbaSpPalette = {
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff, 0x7fff,
|
||||
0x9c00, 0x6340, 0x10c6, 0xdb97, 0x7622, 0x3e57, 0x2e12, 0x95c3,
|
||||
0x1095, 0x488c, 0x8241, 0xde8c, 0xfabc, 0x0e81, 0x7675, 0xfdec,
|
||||
0xddfd, 0x5995, 0x066a, 0xed1e, 0x1e84, 0x1d14, 0x11c3, 0x2749,
|
||||
0xa727, 0x6266, 0xe27b, 0xe3fc, 0x1f76, 0xf158, 0x468e, 0xa540,
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
extern uint8_t* pix;
|
||||
bool gbUpdateSizes();
|
||||
bool inBios = false;
|
||||
|
@ -2184,6 +2223,8 @@ bool CPUIsGBBios(const char* file)
|
|||
const char* p = strrchr(file, '.');
|
||||
|
||||
if (p != NULL) {
|
||||
if (_stricmp(p, ".gbc") == 0)
|
||||
return true;
|
||||
if (_stricmp(p, ".gb") == 0)
|
||||
return true;
|
||||
if (_stricmp(p, ".bin") == 0)
|
||||
|
@ -2315,6 +2356,14 @@ static void gbSelectColorizationPalette()
|
|||
memcpy(gbPalette, gbColorizationPaletteData[palette][2], sizeof(gbColorizationPaletteData[palette][0]));
|
||||
}
|
||||
|
||||
void gbResetPalette() {
|
||||
if (!gbCgbMode && !gbSgbMode) {
|
||||
// In SGB Mode, palette initialization is done in gbSgbReset().
|
||||
memcpy(gbPalette, &systemGbPalette[gbPaletteOption * 8],
|
||||
8 * sizeof(systemGbPalette[0]));
|
||||
}
|
||||
}
|
||||
|
||||
void gbReset()
|
||||
{
|
||||
#ifndef NO_LINK
|
||||
|
@ -2606,10 +2655,9 @@ void gbReset()
|
|||
gbTimerOnChange = false;
|
||||
gbTimerOn = 0;
|
||||
|
||||
if (gbCgbMode) {
|
||||
for (i = 0; i < 0x20; i++)
|
||||
gbPalette[i] = 0x7fff;
|
||||
gbResetPalette();
|
||||
|
||||
if (gbCgbMode) {
|
||||
// This is just to show that the starting values of the OBJ palettes are different
|
||||
// between the 3 consoles, and that they 'kinda' stay the same at each reset
|
||||
// (they can slightly change, somehow (randomly?)).
|
||||
|
@ -2618,122 +2666,21 @@ void gbReset()
|
|||
// is running (GB,GBC and GBA(SP) have different startup values).
|
||||
// Unfortunatly, I don't have any SGB system, so I can't get their starting values.
|
||||
|
||||
if (gbGBCColorType == 0) // GBC Hardware
|
||||
{
|
||||
gbPalette[0x20] = 0x0600;
|
||||
gbPalette[0x21] = 0xfdf3;
|
||||
gbPalette[0x22] = 0x041c;
|
||||
gbPalette[0x23] = 0xf5db;
|
||||
gbPalette[0x24] = 0x4419;
|
||||
gbPalette[0x25] = 0x57ea;
|
||||
gbPalette[0x26] = 0x2808;
|
||||
gbPalette[0x27] = 0x9b75;
|
||||
gbPalette[0x28] = 0x129b;
|
||||
gbPalette[0x29] = 0xfce0;
|
||||
gbPalette[0x2a] = 0x22da;
|
||||
gbPalette[0x2b] = 0x4ac5;
|
||||
gbPalette[0x2c] = 0x2d71;
|
||||
gbPalette[0x2d] = 0xf0c2;
|
||||
gbPalette[0x2e] = 0x5137;
|
||||
gbPalette[0x2f] = 0x2d41;
|
||||
gbPalette[0x30] = 0x6b2d;
|
||||
gbPalette[0x31] = 0x2215;
|
||||
gbPalette[0x32] = 0xbe0a;
|
||||
gbPalette[0x33] = 0xc053;
|
||||
gbPalette[0x34] = 0xfe5f;
|
||||
gbPalette[0x35] = 0xe000;
|
||||
gbPalette[0x36] = 0xbe10;
|
||||
gbPalette[0x37] = 0x914d;
|
||||
gbPalette[0x38] = 0x7f91;
|
||||
gbPalette[0x39] = 0x02b5;
|
||||
gbPalette[0x3a] = 0x77ac;
|
||||
gbPalette[0x3b] = 0x14e5;
|
||||
gbPalette[0x3c] = 0xcf89;
|
||||
gbPalette[0x3d] = 0xa03d;
|
||||
gbPalette[0x3e] = 0xfd50;
|
||||
gbPalette[0x3f] = 0x91ff;
|
||||
} else if (gbGBCColorType == 1) // GBA Hardware
|
||||
{
|
||||
gbPalette[0x20] = 0xbe00;
|
||||
gbPalette[0x21] = 0xfdfd;
|
||||
gbPalette[0x22] = 0xbd69;
|
||||
gbPalette[0x23] = 0x7baf;
|
||||
gbPalette[0x24] = 0xf5ff;
|
||||
gbPalette[0x25] = 0x3f8f;
|
||||
gbPalette[0x26] = 0xcee5;
|
||||
gbPalette[0x27] = 0x5bf7;
|
||||
gbPalette[0x28] = 0xb35b;
|
||||
gbPalette[0x29] = 0xef97;
|
||||
gbPalette[0x2a] = 0xef9f;
|
||||
gbPalette[0x2b] = 0x97f7;
|
||||
gbPalette[0x2c] = 0x82bf;
|
||||
gbPalette[0x2d] = 0x9f3d;
|
||||
gbPalette[0x2e] = 0xddde;
|
||||
gbPalette[0x2f] = 0xbad5;
|
||||
gbPalette[0x30] = 0x3cba;
|
||||
gbPalette[0x31] = 0xdfd7;
|
||||
gbPalette[0x32] = 0xedea;
|
||||
gbPalette[0x33] = 0xfeda;
|
||||
gbPalette[0x34] = 0xf7f9;
|
||||
gbPalette[0x35] = 0xfdee;
|
||||
gbPalette[0x36] = 0x6d2f;
|
||||
gbPalette[0x37] = 0xf0e6;
|
||||
gbPalette[0x38] = 0xf7f0;
|
||||
gbPalette[0x39] = 0xf296;
|
||||
gbPalette[0x3a] = 0x3bf1;
|
||||
gbPalette[0x3b] = 0xe211;
|
||||
gbPalette[0x3c] = 0x69ba;
|
||||
gbPalette[0x3d] = 0x3d0d;
|
||||
gbPalette[0x3e] = 0xdfd3;
|
||||
gbPalette[0x3f] = 0xa6ba;
|
||||
} else if (gbGBCColorType == 2) // GBASP Hardware
|
||||
{
|
||||
gbPalette[0x20] = 0x9c00;
|
||||
gbPalette[0x21] = 0x6340;
|
||||
gbPalette[0x22] = 0x10c6;
|
||||
gbPalette[0x23] = 0xdb97;
|
||||
gbPalette[0x24] = 0x7622;
|
||||
gbPalette[0x25] = 0x3e57;
|
||||
gbPalette[0x26] = 0x2e12;
|
||||
gbPalette[0x27] = 0x95c3;
|
||||
gbPalette[0x28] = 0x1095;
|
||||
gbPalette[0x29] = 0x488c;
|
||||
gbPalette[0x2a] = 0x8241;
|
||||
gbPalette[0x2b] = 0xde8c;
|
||||
gbPalette[0x2c] = 0xfabc;
|
||||
gbPalette[0x2d] = 0x0e81;
|
||||
gbPalette[0x2e] = 0x7675;
|
||||
gbPalette[0x2f] = 0xfdec;
|
||||
gbPalette[0x30] = 0xddfd;
|
||||
gbPalette[0x31] = 0x5995;
|
||||
gbPalette[0x32] = 0x066a;
|
||||
gbPalette[0x33] = 0xed1e;
|
||||
gbPalette[0x34] = 0x1e84;
|
||||
gbPalette[0x35] = 0x1d14;
|
||||
gbPalette[0x36] = 0x11c3;
|
||||
gbPalette[0x37] = 0x2749;
|
||||
gbPalette[0x38] = 0xa727;
|
||||
gbPalette[0x39] = 0x6266;
|
||||
gbPalette[0x3a] = 0xe27b;
|
||||
gbPalette[0x3b] = 0xe3fc;
|
||||
gbPalette[0x3c] = 0x1f76;
|
||||
gbPalette[0x3d] = 0xf158;
|
||||
gbPalette[0x3e] = 0x468e;
|
||||
gbPalette[0x3f] = 0xa540;
|
||||
if (gbGBCColorType == 0) {
|
||||
// GBC Hardware
|
||||
std::copy(kGbGbcPalette.begin(), kGbGbcPalette.end(), gbPalette);
|
||||
} else if (gbGBCColorType == 1) {
|
||||
// GBA Hardware
|
||||
std::copy(kGbGbaPalette.begin(), kGbGbaPalette.end(), gbPalette);
|
||||
} else if (gbGBCColorType == 2) {
|
||||
// GBASP Hardware
|
||||
std::copy(kGbGbaSpPalette.begin(), kGbGbaSpPalette.end(), gbPalette);
|
||||
}
|
||||
|
||||
// The CGB BIOS palette selection has to be done by VBA if BIOS is skipped.
|
||||
if (!(gbRom[0x143] & 0x80) && !inBios) {
|
||||
gbSelectColorizationPalette();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (gbSgbMode) {
|
||||
for (i = 0; i < 8; i++)
|
||||
gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];
|
||||
}
|
||||
for (i = 0; i < 8; i++)
|
||||
gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];
|
||||
}
|
||||
|
||||
GBTIMER_MODE_0_CLOCK_TICKS = 256;
|
||||
|
@ -3985,12 +3932,9 @@ static bool gbReadSaveState(gzFile gzFile)
|
|||
if (version < 11)
|
||||
utilGzRead(gzFile, gbPalette, 128 * sizeof(uint16_t));
|
||||
|
||||
if (version < GBSAVE_GAME_VERSION_10) {
|
||||
if (!gbCgbMode && !gbSgbMode) {
|
||||
for (int i = 0; i < 8; i++)
|
||||
gbPalette[i] = systemGbPalette[gbPaletteOption * 8 + i];
|
||||
}
|
||||
}
|
||||
// This is necessary for GB games (not GBC or SGB) to have them load with
|
||||
// the user-defined palette and not the saved palette.
|
||||
gbResetPalette();
|
||||
|
||||
utilGzRead(gzFile, &gbMemory[0x8000], 0x8000);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef GB_H
|
||||
#define GB_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#define gbWidth 160
|
||||
#define gbHeight 144
|
||||
#define sgbWidth 256
|
||||
|
@ -33,6 +35,12 @@ void gbWriteMemory(uint16_t, uint8_t);
|
|||
void gbDrawLine();
|
||||
bool gbIsGameboyRom(const char*);
|
||||
void gbGetHardwareType();
|
||||
|
||||
// Resets gbPalette to systemGbPalette and gbPaletteOption value. This is called
|
||||
// in gbReset and only needs to be called when systemGbPalette or
|
||||
// gbPaletteOption is updated while a GB game is running.
|
||||
void gbResetPalette();
|
||||
|
||||
void gbReset();
|
||||
void gbCleanUp();
|
||||
void gbCPUInit(const char*, bool);
|
||||
|
|
|
@ -27,14 +27,14 @@ bool genericflashcardEnable = false;
|
|||
int gbCgbMode = 0;
|
||||
|
||||
uint16_t gbColorFilter[32768];
|
||||
int gbColorOption = 0;
|
||||
int gbPaletteOption = 0;
|
||||
int gbEmulatorType = 0;
|
||||
int gbBorderOn = 0;
|
||||
int gbBorderAutomatic = 0;
|
||||
uint32_t gbEmulatorType = 0;
|
||||
uint32_t gbPaletteOption = 0;
|
||||
int gbBorderLineSkip = 160;
|
||||
int gbBorderRowSkip = 0;
|
||||
int gbBorderColumnSkip = 0;
|
||||
int gbDmaTicks = 0;
|
||||
bool gbBorderAutomatic = false;
|
||||
bool gbBorderOn = false;
|
||||
bool gbColorOption = false;
|
||||
|
||||
uint8_t (*gbSerialFunction)(uint8_t) = NULL;
|
||||
|
|
|
@ -23,11 +23,8 @@ extern uint8_t* gbMemoryMap[16];
|
|||
|
||||
extern int gbFrameSkip;
|
||||
extern uint16_t gbColorFilter[32768];
|
||||
extern int gbColorOption;
|
||||
extern int gbPaletteOption;
|
||||
extern int gbEmulatorType;
|
||||
extern int gbBorderOn;
|
||||
extern int gbBorderAutomatic;
|
||||
extern uint32_t gbEmulatorType;
|
||||
extern uint32_t gbPaletteOption;
|
||||
extern int gbCgbMode;
|
||||
extern int gbSgbMode;
|
||||
extern int gbWindowLine;
|
||||
|
@ -36,8 +33,10 @@ extern uint8_t gbBgp[4];
|
|||
extern uint8_t gbObp0[4];
|
||||
extern uint8_t gbObp1[4];
|
||||
extern uint16_t gbPalette[128];
|
||||
extern bool gbBorderAutomatic;
|
||||
extern bool gbBorderOn;
|
||||
extern bool gbColorOption;
|
||||
extern bool gbScreenOn;
|
||||
extern bool gbDrawWindow;
|
||||
extern uint8_t gbSCYLine[300];
|
||||
// gbSCXLine is used for the emulation (bug) of the SX change
|
||||
// found in the Artic Zone game.
|
||||
|
|
|
@ -319,7 +319,7 @@ void gbSgbPicture()
|
|||
gbSgbCGBSupport |= 4;
|
||||
|
||||
if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) {
|
||||
gbBorderOn = 1;
|
||||
gbBorderOn = true;
|
||||
systemGbBorderOn();
|
||||
}
|
||||
|
||||
|
@ -663,7 +663,7 @@ void gbSgbChrTransfer()
|
|||
memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32);
|
||||
|
||||
if (gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4) {
|
||||
gbBorderOn = 1;
|
||||
gbBorderOn = true;
|
||||
systemGbBorderOn();
|
||||
}
|
||||
|
||||
|
|
|
@ -1067,14 +1067,14 @@ static void update_variables(bool startup)
|
|||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
|
||||
if (strcmp(var.value, "auto") == 0) {
|
||||
gbBorderAutomatic = 1;
|
||||
gbBorderAutomatic = true;
|
||||
}
|
||||
else if (!strcmp(var.value, "enabled")) {
|
||||
gbBorderAutomatic = 0;
|
||||
gbBorderOn = 1;
|
||||
gbBorderAutomatic = false;
|
||||
gbBorderOn = false;
|
||||
} else { // disabled
|
||||
gbBorderOn = 0;
|
||||
gbBorderAutomatic = 0;
|
||||
gbBorderOn = true;
|
||||
gbBorderAutomatic = false;
|
||||
}
|
||||
|
||||
if ((type == IMAGE_GB) && !startup)
|
||||
|
@ -1179,7 +1179,7 @@ static void update_variables(bool startup)
|
|||
var.value = NULL;
|
||||
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
|
||||
gbColorOption = (!strcmp(var.value, "enabled")) ? 1 : 0;
|
||||
gbColorOption = (!strcmp(var.value, "enabled"));
|
||||
}
|
||||
|
||||
var.key = "vbam_lcdfilter";
|
||||
|
|
|
@ -69,6 +69,9 @@ enum named_opts
|
|||
OPT_CPU_SAVE_TYPE,
|
||||
OPT_DOTCODE_FILE_NAME_LOAD,
|
||||
OPT_DOTCODE_FILE_NAME_SAVE,
|
||||
OPT_GB_BORDER_AUTOMATIC,
|
||||
OPT_GB_BORDER_ON,
|
||||
OPT_GB_COLOR_OPTION,
|
||||
OPT_GB_EMULATOR_TYPE,
|
||||
OPT_GB_FRAME_SKIP,
|
||||
OPT_GB_PALETTE_OPTION,
|
||||
|
@ -147,12 +150,12 @@ struct option argOptions[] = {
|
|||
{ "bios-file-name-gb", required_argument, 0, OPT_BIOS_FILE_NAME_GB },
|
||||
{ "bios-file-name-gba", required_argument, 0, OPT_BIOS_FILE_NAME_GBA },
|
||||
{ "bios-file-name-gbc", required_argument, 0, OPT_BIOS_FILE_NAME_GBC },
|
||||
{ "border-automatic", no_argument, &gbBorderAutomatic, 1 },
|
||||
{ "border-on", no_argument, &gbBorderOn, 1 },
|
||||
{ "border-automatic", no_argument, 0, OPT_GB_BORDER_AUTOMATIC },
|
||||
{ "border-on", no_argument, 0, OPT_GB_BORDER_ON },
|
||||
{ "capture-format", required_argument, 0, OPT_CAPTURE_FORMAT },
|
||||
{ "cheat", required_argument, 0, OPT_CHEAT },
|
||||
{ "cheats-enabled", no_argument, &coreOptions.cheatsEnabled, 1 },
|
||||
{ "color-option", no_argument, &gbColorOption, 1 },
|
||||
{ "color-option", no_argument, 0, OPT_GB_COLOR_OPTION },
|
||||
{ "config", required_argument, 0, 'c' },
|
||||
{ "cpu-disable-sfx", no_argument, &coreOptions.cpuDisableSfx, 1 },
|
||||
{ "cpu-save-type", required_argument, 0, OPT_CPU_SAVE_TYPE },
|
||||
|
@ -167,9 +170,9 @@ struct option argOptions[] = {
|
|||
{ "flash-size", required_argument, 0, 'S' },
|
||||
{ "frameskip", required_argument, 0, 's' },
|
||||
{ "full-screen", no_argument, &fullScreen, 1 },
|
||||
{ "gb-border-automatic", no_argument, &gbBorderAutomatic, 1 },
|
||||
{ "gb-border-on", no_argument, &gbBorderOn, 1 },
|
||||
{ "gb-color-option", no_argument, &gbColorOption, 1 },
|
||||
{ "gb-border-automatic", no_argument, 0, OPT_GB_BORDER_AUTOMATIC },
|
||||
{ "gb-border-on", no_argument, 0, OPT_GB_BORDER_ON },
|
||||
{ "gb-color-option", no_argument, 0, OPT_GB_COLOR_OPTION },
|
||||
{ "gb-emulator-type", required_argument, 0, OPT_GB_EMULATOR_TYPE },
|
||||
{ "gb-frame-skip", required_argument, 0, OPT_GB_FRAME_SKIP },
|
||||
{ "gb-palette-option", required_argument, 0, OPT_GB_PALETTE_OPTION },
|
||||
|
@ -257,8 +260,10 @@ void OpenPreferences(const char *name)
|
|||
|
||||
void ValidateConfig()
|
||||
{
|
||||
if (gbEmulatorType < 0 || gbEmulatorType > 5)
|
||||
if (gbEmulatorType > 5)
|
||||
gbEmulatorType = 1;
|
||||
if (gbPaletteOption > 2)
|
||||
gbPaletteOption = 0;
|
||||
if (frameSkip < 0 || frameSkip > 9)
|
||||
frameSkip = 2;
|
||||
if (gbFrameSkip < 0 || gbFrameSkip > 9)
|
||||
|
@ -863,6 +868,24 @@ int ReadOpts(int argc, char ** argv)
|
|||
}
|
||||
break;
|
||||
|
||||
case OPT_GB_BORDER_AUTOMATIC:
|
||||
// --border-automatic
|
||||
// --gb-border-automatic
|
||||
gbBorderAutomatic = true;
|
||||
break;
|
||||
|
||||
case OPT_GB_BORDER_ON:
|
||||
// --border-on
|
||||
// --gb-border-on
|
||||
gbBorderOn = true;
|
||||
break;
|
||||
|
||||
case OPT_GB_COLOR_OPTION:
|
||||
// --color-option
|
||||
// --gb-color-option
|
||||
gbColorOption = true;
|
||||
break;
|
||||
|
||||
case OPT_GB_EMULATOR_TYPE:
|
||||
// --gb-emulator-type
|
||||
if (optarg) {
|
||||
|
|
|
@ -1562,7 +1562,7 @@ int main(int argc, char** argv)
|
|||
SetHomeDataDir();
|
||||
|
||||
frameSkip = 2;
|
||||
gbBorderOn = 0;
|
||||
gbBorderOn = false;
|
||||
|
||||
coreOptions.parseDebug = true;
|
||||
|
||||
|
|
|
@ -765,6 +765,8 @@ set(
|
|||
config/option.cpp
|
||||
config/user-input.cpp
|
||||
dialogs/display-config.cpp
|
||||
dialogs/game-boy-config.cpp
|
||||
widgets/group-check-box.cpp
|
||||
widgets/keep-on-top-styler.cpp
|
||||
widgets/keyedit.cpp
|
||||
widgets/joyedit.cpp
|
||||
|
@ -811,7 +813,10 @@ set(
|
|||
config/option.h
|
||||
config/user-input.h
|
||||
dialogs/display-config.h
|
||||
dialogs/game-boy-config.h
|
||||
dialogs/validated-child.h
|
||||
widgets/dpi-support.h
|
||||
widgets/group-check-box.h
|
||||
widgets/keep-on-top-styler.h
|
||||
widgets/option-validator.h
|
||||
widgets/render-plugin.h
|
||||
|
|
|
@ -2492,50 +2492,7 @@ EVT_HANDLER(UIConfigure, "UI Settings...")
|
|||
|
||||
EVT_HANDLER(GameBoyConfigure, "Game Boy options...")
|
||||
{
|
||||
wxDialog* dlg = GetXRCDialog("GameBoyConfig");
|
||||
wxChoice* c = XRCCTRL(*dlg, "Borders", wxChoice);
|
||||
bool borderon = gbBorderOn;
|
||||
|
||||
if (!gbBorderOn && !gbBorderAutomatic)
|
||||
c->SetSelection(0);
|
||||
else if (gbBorderOn)
|
||||
c->SetSelection(1);
|
||||
else
|
||||
c->SetSelection(2);
|
||||
|
||||
if (ShowModal(dlg) != wxID_OK)
|
||||
return;
|
||||
|
||||
switch (c->GetSelection()) {
|
||||
case 0:
|
||||
gbBorderOn = gbBorderAutomatic = false;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gbBorderOn = true;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gbBorderOn = false;
|
||||
gbBorderAutomatic = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// this value might have been overwritten by FrameSkip
|
||||
if (panel->game_type() == IMAGE_GB) {
|
||||
if (borderon != gbBorderOn) {
|
||||
if (gbBorderOn) {
|
||||
panel->AddBorder();
|
||||
gbSgbRenderBorder();
|
||||
} else
|
||||
panel->DelBorder();
|
||||
}
|
||||
|
||||
// don't want to have to reset to change colors
|
||||
memcpy(gbPalette, &systemGbPalette[gbPaletteOption * 8], 8 * sizeof(systemGbPalette[0]));
|
||||
}
|
||||
|
||||
update_opts();
|
||||
ShowModal(GetXRCDialog("GameBoyConfig"));
|
||||
}
|
||||
|
||||
EVT_HANDLER(SetSize1x, "1x")
|
||||
|
@ -3027,13 +2984,7 @@ EVT_HANDLER_MASK(GBLcdFilter, "Enable LCD filter", CMDEN_GB)
|
|||
|
||||
EVT_HANDLER(GBColorOption, "Enable GB color option")
|
||||
{
|
||||
bool menuPress = false;
|
||||
bool intVar = gbColorOption ? true : false;
|
||||
GetMenuOptionBool("GBColorOption", &menuPress);
|
||||
toggleBooleanVar(&menuPress, &intVar);
|
||||
SetMenuOption("GBColorOption", intVar ? 1 : 0);
|
||||
gbColorOption = intVar ? 1 : 0;
|
||||
update_opts();
|
||||
GetMenuOptionConfig("GBColorOption", config::OptionID::kGBColorOption);
|
||||
}
|
||||
|
||||
EVT_HANDLER(ApplyPatches, "Apply IPS/UPS/IPF patches if found")
|
||||
|
|
|
@ -162,7 +162,9 @@ std::array<Option, kNbOptions>& Option::All() {
|
|||
bool retain_aspect = true;
|
||||
|
||||
/// GB
|
||||
wxString gb_bios = wxEmptyString;
|
||||
bool colorizer_hack = false;
|
||||
wxString gbc_bios = wxEmptyString;
|
||||
|
||||
/// Core
|
||||
bool agb_print = false;
|
||||
|
@ -212,11 +214,11 @@ std::array<Option, kNbOptions>& Option::All() {
|
|||
Option(OptionID::kDispStretch, &g_owned_opts.retain_aspect),
|
||||
|
||||
/// GB
|
||||
Option(OptionID::kGBBiosFile, &gopts.gb_bios),
|
||||
Option(OptionID::kGBColorOption, &gbColorOption, 0, 1),
|
||||
Option(OptionID::kGBBiosFile, &g_owned_opts.gb_bios),
|
||||
Option(OptionID::kGBColorOption, &gbColorOption),
|
||||
Option(OptionID::kGBColorizerHack, &g_owned_opts.colorizer_hack),
|
||||
Option(OptionID::kGBLCDFilter, &gopts.gb_lcd_filter),
|
||||
Option(OptionID::kGBGBCBiosFile, &gopts.gbc_bios),
|
||||
Option(OptionID::kGBGBCBiosFile, &g_owned_opts.gbc_bios),
|
||||
Option(OptionID::kGBPalette0, systemGbPalette),
|
||||
Option(OptionID::kGBPalette1, systemGbPalette + 8),
|
||||
Option(OptionID::kGBPalette2, systemGbPalette + 16),
|
||||
|
@ -264,8 +266,8 @@ std::array<Option, kNbOptions>& Option::All() {
|
|||
Option(OptionID::kPrefAutoFrameSkip, &g_owned_opts.auto_frame_skip),
|
||||
Option(OptionID::kPrefAutoPatch, &g_owned_opts.auto_patch),
|
||||
Option(OptionID::kPrefAutoSaveLoadCheatList, &gopts.autoload_cheats),
|
||||
Option(OptionID::kPrefBorderAutomatic, &gbBorderAutomatic, 0, 1),
|
||||
Option(OptionID::kPrefBorderOn, &gbBorderOn, 0, 1),
|
||||
Option(OptionID::kPrefBorderAutomatic, &gbBorderAutomatic),
|
||||
Option(OptionID::kPrefBorderOn, &gbBorderOn),
|
||||
Option(OptionID::kPrefCaptureFormat, &g_owned_opts.capture_format, 0, 1),
|
||||
Option(OptionID::kPrefCheatsEnabled, &coreOptions.cheatsEnabled, 0, 1),
|
||||
Option(OptionID::kPrefDisableStatus, &g_owned_opts.disable_status_messages),
|
||||
|
|
|
@ -23,7 +23,7 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
|
|||
|
||||
/// GB
|
||||
/*kGBBiosFile*/ Option::Type::kString,
|
||||
/*kGBColorOption*/ Option::Type::kInt,
|
||||
/*kGBColorOption*/ Option::Type::kBool,
|
||||
/*kGBColorizerHack*/ Option::Type::kBool,
|
||||
/*kGBLCDFilter*/ Option::Type::kBool,
|
||||
/*kGBGBCBiosFile*/ Option::Type::kString,
|
||||
|
@ -74,15 +74,15 @@ static constexpr std::array<Option::Type, kNbOptions> kOptionsTypes = {
|
|||
/*kPrefAutoFrameSkip*/ Option::Type::kBool,
|
||||
/*kPrefAutoPatch*/ Option::Type::kBool,
|
||||
/*kPrefAutoSaveLoadCheatList*/ Option::Type::kBool,
|
||||
/*kPrefBorderAutomatic*/ Option::Type::kInt,
|
||||
/*kPrefBorderOn*/ Option::Type::kInt,
|
||||
/*kPrefBorderAutomatic*/ Option::Type::kBool,
|
||||
/*kPrefBorderOn*/ Option::Type::kBool,
|
||||
/*kPrefCaptureFormat*/ Option::Type::kUnsigned,
|
||||
/*kPrefCheatsEnabled*/ Option::Type::kInt,
|
||||
/*kPrefDisableStatus*/ Option::Type::kBool,
|
||||
/*kPrefEmulatorType*/ Option::Type::kInt,
|
||||
/*kPrefEmulatorType*/ Option::Type::kUnsigned,
|
||||
/*kPrefFlashSize*/ Option::Type::kUnsigned,
|
||||
/*kPrefFrameSkip*/ Option::Type::kInt,
|
||||
/*kPrefGBPaletteOption*/ Option::Type::kInt,
|
||||
/*kPrefGBPaletteOption*/ Option::Type::kUnsigned,
|
||||
/*kPrefGBPrinter*/ Option::Type::kInt,
|
||||
/*kPrefGDBBreakOnLoad*/ Option::Type::kBool,
|
||||
/*kPrefGDBPort*/ Option::Type::kInt,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "config/option.h"
|
||||
|
||||
#include <cstring>
|
||||
#include "nonstd/variant.hpp"
|
||||
|
||||
#include <wx/log.h>
|
||||
|
@ -287,6 +288,15 @@ wxString Option::GetEnumString() const {
|
|||
return wxEmptyString;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 8> Option::GetGbPalette() const {
|
||||
assert(is_gb_palette());
|
||||
|
||||
const uint16_t* raw_palette = (nonstd::get<uint16_t*>(value_));
|
||||
std::array<uint16_t, 8> palette;
|
||||
std::memcpy(palette.data(), raw_palette, sizeof(palette));
|
||||
return palette;
|
||||
}
|
||||
|
||||
wxString Option::GetGbPaletteString() const {
|
||||
assert(is_gb_palette());
|
||||
|
||||
|
@ -454,7 +464,25 @@ bool Option::SetEnumInt(int value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Option::SetGbPalette(const wxString& value) {
|
||||
bool Option::SetGbPalette(const std::array<uint16_t, 8>& value) {
|
||||
assert(is_gb_palette());
|
||||
|
||||
uint16_t* dest = nonstd::get<uint16_t*>(value_);
|
||||
|
||||
// Keep a copy of the current value.
|
||||
std::array<uint16_t, 8> old_value;
|
||||
std::copy(dest, dest + 8, old_value.data());
|
||||
|
||||
// Set the new value.
|
||||
std::copy(value.begin(), value.end(), dest);
|
||||
|
||||
if (old_value != value) {
|
||||
CallObservers();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Option::SetGbPaletteString(const wxString& value) {
|
||||
assert(is_gb_palette());
|
||||
|
||||
// 8 values of 4 chars and 7 commas.
|
||||
|
@ -465,10 +493,6 @@ bool Option::SetGbPalette(const wxString& value) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint16_t* dest = nonstd::get<uint16_t*>(value_);
|
||||
std::array<uint16_t, 8> old_value;
|
||||
std::copy(dest, dest + 8, old_value.data());
|
||||
|
||||
std::array<uint16_t, 8> new_value;
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
wxString number = value.substr(i * 5, 4);
|
||||
|
@ -477,12 +501,8 @@ bool Option::SetGbPalette(const wxString& value) {
|
|||
new_value[i] = temp;
|
||||
}
|
||||
}
|
||||
std::copy(new_value.begin(), new_value.end(), dest);
|
||||
|
||||
if (old_value != new_value) {
|
||||
CallObservers();
|
||||
}
|
||||
return true;
|
||||
return SetGbPalette(new_value);
|
||||
}
|
||||
|
||||
double Option::GetDoubleMin() const {
|
||||
|
|
|
@ -180,6 +180,7 @@ public:
|
|||
Interframe GetInterframe() const;
|
||||
RenderMethod GetRenderMethod() const;
|
||||
wxString GetEnumString() const;
|
||||
std::array<uint16_t, 8> GetGbPalette() const;
|
||||
wxString GetGbPaletteString() const;
|
||||
|
||||
// Sets the value. Will assert on type mismatch.
|
||||
|
@ -194,7 +195,8 @@ public:
|
|||
bool SetInterframe(const Interframe& value);
|
||||
bool SetRenderMethod(const RenderMethod& value);
|
||||
bool SetEnumString(const wxString& value);
|
||||
bool SetGbPalette(const wxString& value);
|
||||
bool SetGbPalette(const std::array<uint16_t, 8>& value);
|
||||
bool SetGbPaletteString(const wxString& value);
|
||||
|
||||
// Min/Max accessors.
|
||||
double GetDoubleMin() const;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "config/option-id.h"
|
||||
#include "config/option-proxy.h"
|
||||
#include "config/option.h"
|
||||
#include "keep-on-top-styler.h"
|
||||
#include "dialogs/validated-child.h"
|
||||
#include "rpi.h"
|
||||
#include "wayland.h"
|
||||
#include "widgets/option-validator.h"
|
||||
|
@ -218,20 +218,6 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// Helper functions to assert on the returned value.
|
||||
wxWindow* GetValidatedChild(const wxWindow* parent, const wxString& name) {
|
||||
wxWindow* window = parent->FindWindow(name);
|
||||
assert(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* GetValidatedChild(const wxWindow* parent, const wxString& name) {
|
||||
T* child = wxDynamicCast(GetValidatedChild(parent, name), T);
|
||||
assert(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
#include "dialogs/game-boy-config.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/choice.h>
|
||||
#include <wx/clrpicker.h>
|
||||
#include <wx/filepicker.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/stattext.h>
|
||||
|
||||
#include <wx/xrc/xmlres.h>
|
||||
|
||||
#include "config/option-observer.h"
|
||||
#include "config/option-proxy.h"
|
||||
#include "dialogs/validated-child.h"
|
||||
#include "widgets/group-check-box.h"
|
||||
#include "widgets/option-validator.h"
|
||||
#include "wx/object.h"
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
namespace {
|
||||
|
||||
static constexpr size_t kNbPalettes = 3;
|
||||
|
||||
// These are the choices for canned colors; their order must match the names in
|
||||
// wxChoice control.
|
||||
// clang-format off
|
||||
static constexpr std::array<std::array<uint16_t, 8>, 9> kDefaultPalettes = {{
|
||||
// Standard
|
||||
{0x7FFF, 0x56B5, 0x318C, 0x0000, 0x7FFF, 0x56B5, 0x318C, 0x0000},
|
||||
// Blue Sea
|
||||
{0x6200, 0x7E10, 0x7C10, 0x5000, 0x6200, 0x7E10, 0x7C10, 0x5000},
|
||||
// Dark Night
|
||||
{0x4008, 0x4000, 0x2000, 0x2008, 0x4008, 0x4000, 0x2000, 0x2008},
|
||||
// Green Forest
|
||||
{0x43F0, 0x03E0, 0x4200, 0x2200, 0x43F0, 0x03E0, 0x4200, 0x2200},
|
||||
// Hot Desert
|
||||
{0x43FF, 0x03FF, 0x221F, 0x021F, 0x43FF, 0x03FF, 0x221F, 0x021F},
|
||||
// Pink Dreams
|
||||
{0x621F, 0x7E1F, 0x7C1F, 0x2010, 0x621F, 0x7E1F, 0x7C1F, 0x2010},
|
||||
// Weird Colors
|
||||
{0x621F, 0x401F, 0x001F, 0x2010, 0x621F, 0x401F, 0x001F, 0x2010},
|
||||
// Real GB Colors
|
||||
{0x1B8E, 0x02C0, 0x0DA0, 0x1140, 0x1B8E, 0x02C0, 0x0DA0, 0x1140},
|
||||
// Real 'GB on GBASP' Colors
|
||||
// TODO: Figure out what the commented out values mean.
|
||||
{0x7BDE, /*0x23F0*/ 0x5778, /*0x5DC0*/ 0x5640, 0x0000, 0x7BDE, /*0x3678*/ 0x529C, /*0x0980*/ 0x2990, 0x0000},
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
// This is a custom wxClientData held by wxPanels implementing the
|
||||
// GBColorPrefPanel panel. This takes care of setting the wxPanel with the
|
||||
// appropriate event handlers and validators for its internal widgets.
|
||||
class GBPalettePanelData final : public wxClientData {
|
||||
public:
|
||||
GBPalettePanelData(wxPanel* panel, size_t palette_id);
|
||||
~GBPalettePanelData() final = default;
|
||||
|
||||
private:
|
||||
// Update `colour_pickers_` to match the `palette_` value and reset
|
||||
// `default_selector_` if the current palette corresponds to one of the
|
||||
// default palettes.
|
||||
void UpdateColourPickers();
|
||||
|
||||
// Callback for the `colour_pickers_` wxEVT_COLOURPICKER_CHANGED events.
|
||||
void OnColourChanged(size_t colour_index, wxColourPickerEvent& event);
|
||||
|
||||
// Callback for the `default_selector_` wxEVT_CHOICE events.
|
||||
void OnDefaultPaletteSelected(wxCommandEvent& event);
|
||||
|
||||
// Callback for the "Reset" wxButton event.
|
||||
void OnPaletteReset(wxCommandEvent& event);
|
||||
|
||||
wxChoice* const default_selector_;
|
||||
const config::OptionID option_id_;
|
||||
|
||||
std::array<wxColourPickerCtrl*, 8> colour_pickers_;
|
||||
std::array<uint16_t, 8> palette_;
|
||||
|
||||
friend class PaletteValidator;
|
||||
};
|
||||
|
||||
// Custom validator for kGbPalette options. The "work" palette is held by the
|
||||
// GBPalettePanelData object attached to this wxPanel.
|
||||
class PaletteValidator final : public widgets::OptionValidator {
|
||||
public:
|
||||
PaletteValidator(GBPalettePanelData* palette_data)
|
||||
: widgets::OptionValidator(palette_data->option_id_),
|
||||
palette_data_(palette_data) {
|
||||
assert(option()->is_gb_palette());
|
||||
assert(palette_data);
|
||||
}
|
||||
~PaletteValidator() final = default;
|
||||
|
||||
private:
|
||||
// widgets::OptionValidator implementation.
|
||||
wxObject* Clone() const final {
|
||||
return new PaletteValidator(palette_data_);
|
||||
}
|
||||
|
||||
bool IsWindowValueValid() final { return true; }
|
||||
|
||||
bool WriteToWindow() final {
|
||||
palette_data_->palette_ = option()->GetGbPalette();
|
||||
palette_data_->UpdateColourPickers();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteToOption() final {
|
||||
return option()->SetGbPalette(palette_data_->palette_);
|
||||
}
|
||||
|
||||
GBPalettePanelData* const palette_data_;
|
||||
};
|
||||
|
||||
// Custom validator for a kString Option and a wxFilePickerCtrl widget. This
|
||||
// also updates "label" to display the file currently saved as the BIOS.
|
||||
class BIOSPickerValidator final : public widgets::OptionValidator {
|
||||
public:
|
||||
BIOSPickerValidator(config::OptionID option_id, wxStaticText* label)
|
||||
: widgets::OptionValidator(option_id), label_(label) {
|
||||
assert(label_);
|
||||
assert(option()->is_string());
|
||||
}
|
||||
~BIOSPickerValidator() final = default;
|
||||
|
||||
private:
|
||||
// widgets::OptionValidator implementation.
|
||||
wxObject* Clone() const final {
|
||||
return new BIOSPickerValidator(option()->id(), label_);
|
||||
}
|
||||
|
||||
bool IsWindowValueValid() final { return true; }
|
||||
|
||||
bool WriteToWindow() final {
|
||||
const wxString& selection = option()->GetString();
|
||||
|
||||
if (selection.empty()) {
|
||||
label_->SetLabel(_("(None)"));
|
||||
} else {
|
||||
wxFilePickerCtrl* file_picker =
|
||||
wxDynamicCast(GetWindow(), wxFilePickerCtrl);
|
||||
assert(file_picker);
|
||||
file_picker->SetPath(selection);
|
||||
label_->SetLabel(selection);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteToOption() final {
|
||||
const wxFilePickerCtrl* file_picker =
|
||||
wxDynamicCast(GetWindow(), wxFilePickerCtrl);
|
||||
assert(file_picker);
|
||||
return option()->SetString(file_picker->GetPath());
|
||||
}
|
||||
|
||||
wxStaticText* label_;
|
||||
};
|
||||
|
||||
// Custom validator for the kPrefBorderOn and kPrefBorderAutomatic Options.
|
||||
// These Options are controlled by a single wxChoice widget and are only ever
|
||||
// updated by this dialog so we don't need to observe them.
|
||||
class BorderSelectorValidator final : public wxValidator {
|
||||
public:
|
||||
BorderSelectorValidator() = default;
|
||||
~BorderSelectorValidator() final = default;
|
||||
|
||||
private:
|
||||
// wxValidator implementation.
|
||||
wxObject* Clone() const final { return new BorderSelectorValidator(); }
|
||||
|
||||
bool TransferFromWindow() final {
|
||||
const wxChoice* borders_selector = wxDynamicCast(GetWindow(), wxChoice);
|
||||
assert(borders_selector);
|
||||
switch (borders_selector->GetSelection()) {
|
||||
case 0:
|
||||
OPTION(kPrefBorderOn) = false;
|
||||
OPTION(kPrefBorderAutomatic) = false;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
OPTION(kPrefBorderOn) = true;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
OPTION(kPrefBorderOn) = false;
|
||||
OPTION(kPrefBorderAutomatic) = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Validate(wxWindow*) final { return true; }
|
||||
|
||||
bool TransferToWindow() final {
|
||||
wxChoice* borders_selector = wxDynamicCast(GetWindow(), wxChoice);
|
||||
assert(borders_selector);
|
||||
|
||||
if (!OPTION(kPrefBorderOn) && !OPTION(kPrefBorderAutomatic)) {
|
||||
borders_selector->SetSelection(0);
|
||||
} else if (OPTION(kPrefBorderOn)) {
|
||||
borders_selector->SetSelection(1);
|
||||
} else {
|
||||
borders_selector->SetSelection(2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if WX_HAS_VALIDATOR_SET_WINDOW_OVERRIDE
|
||||
void SetWindow(wxWindow* window) final {
|
||||
wxValidator::SetWindow(window);
|
||||
TransferToWindow();
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
GBPalettePanelData::GBPalettePanelData(wxPanel* panel, size_t palette_id)
|
||||
: wxClientData(),
|
||||
default_selector_(GetValidatedChild<wxChoice>(panel, "DefaultPalette")),
|
||||
option_id_(static_cast<config::OptionID>(
|
||||
static_cast<size_t>(config::OptionID::kGBPalette0) + palette_id)) {
|
||||
assert(panel);
|
||||
assert(palette_id < kNbPalettes);
|
||||
|
||||
default_selector_->Bind(
|
||||
wxEVT_CHOICE, &GBPalettePanelData::OnDefaultPaletteSelected, this);
|
||||
|
||||
GetValidatedChild<wxCheckBox>(panel, "UsePalette")
|
||||
->SetValidator(widgets::OptionSelectedValidator(
|
||||
config::OptionID::kPrefGBPaletteOption, palette_id));
|
||||
|
||||
for (size_t i = 0; i < colour_pickers_.size(); i++) {
|
||||
wxColourPickerCtrl* colour_picker =
|
||||
GetValidatedChild<wxColourPickerCtrl>(
|
||||
panel, wxString::Format("Color%zu", i));
|
||||
colour_pickers_[i] = colour_picker;
|
||||
|
||||
// Update the internal palette reference on colour change.
|
||||
colour_picker->Bind(wxEVT_COLOURPICKER_CHANGED,
|
||||
std::bind(&GBPalettePanelData::OnColourChanged,
|
||||
this, i, std::placeholders::_1),
|
||||
colour_picker->GetId());
|
||||
}
|
||||
|
||||
GetValidatedChild(panel, "Reset")
|
||||
->Bind(wxEVT_BUTTON, &GBPalettePanelData::OnPaletteReset, this);
|
||||
}
|
||||
|
||||
void GBPalettePanelData::UpdateColourPickers() {
|
||||
// Update all of the wxColourPickers based on the current palette values.
|
||||
for (size_t i = 0; i < palette_.size(); i++) {
|
||||
const uint16_t element = palette_[i];
|
||||
colour_pickers_[i]->SetColour(wxColour(((element << 3) & 0xf8),
|
||||
((element >> 2) & 0xf8),
|
||||
((element >> 7) & 0xf8)));
|
||||
}
|
||||
|
||||
// See if the current palette corresponds to a default palette.
|
||||
for (size_t i = 0; i < kDefaultPalettes.size(); i++) {
|
||||
if (palette_ == kDefaultPalettes[i]) {
|
||||
default_selector_->SetSelection(i + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The configuration is not a default palette, set it to "Custom".
|
||||
default_selector_->SetSelection(0);
|
||||
}
|
||||
|
||||
void GBPalettePanelData::OnColourChanged(size_t colour_index,
|
||||
wxColourPickerEvent& event) {
|
||||
assert(colour_index < palette_.size());
|
||||
|
||||
// Update the colour value.
|
||||
const wxColour colour = event.GetColour();
|
||||
palette_[colour_index] = ((colour.Red() & 0xf8) >> 3) +
|
||||
((colour.Green() & 0xf8) << 2) +
|
||||
((colour.Blue() & 0xf8) << 7);
|
||||
|
||||
// Reflect changes to the user.
|
||||
UpdateColourPickers();
|
||||
|
||||
// Let the event propagate.
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void GBPalettePanelData::OnDefaultPaletteSelected(wxCommandEvent& event) {
|
||||
if (event.GetSelection() > 0) {
|
||||
// Update the palette to one of the default palettes.
|
||||
palette_ = kDefaultPalettes[event.GetSelection() - 1];
|
||||
UpdateColourPickers();
|
||||
}
|
||||
|
||||
// Let the event propagate.
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void GBPalettePanelData::OnPaletteReset(wxCommandEvent& event) {
|
||||
// Reset the palette to the last user-saved value.
|
||||
palette_ = config::Option::ByID(option_id_)->GetGbPalette();
|
||||
UpdateColourPickers();
|
||||
|
||||
// Let the event propagate.
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
GameBoyConfig* GameBoyConfig::NewInstance(wxWindow* parent) {
|
||||
assert(parent);
|
||||
return new GameBoyConfig(parent);
|
||||
}
|
||||
|
||||
GameBoyConfig::GameBoyConfig(wxWindow* parent)
|
||||
: wxDialog(), keep_on_top_styler_(this) {
|
||||
#if !wxCHECK_VERSION(3, 1, 0)
|
||||
// This needs to be set before loading any element on the window. This also
|
||||
// has no effect since wx 3.1.0, where it became the default.
|
||||
this->SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY);
|
||||
#endif
|
||||
wxXmlResource::Get()->LoadDialog(this, parent, "GameBoyConfig");
|
||||
|
||||
// System and Peripherals.
|
||||
GetValidatedChild(this, "System")
|
||||
->SetValidator(widgets::OptionChoiceValidator(
|
||||
config::OptionID::kPrefEmulatorType));
|
||||
|
||||
// "Display borders" corresponds to 2 variables.
|
||||
GetValidatedChild(this, "Borders")->SetValidator(BorderSelectorValidator());
|
||||
|
||||
// GB BIOS ROM
|
||||
GetValidatedChild(this, "GBBiosPicker")
|
||||
->SetValidator(BIOSPickerValidator(
|
||||
config::OptionID::kGBBiosFile,
|
||||
GetValidatedChild<wxStaticText>(this, "GBBiosLabel")));
|
||||
|
||||
// GBC BIOS ROM
|
||||
GetValidatedChild(this, "GBCBiosPicker")
|
||||
->SetValidator(BIOSPickerValidator(
|
||||
config::OptionID::kGBGBCBiosFile,
|
||||
GetValidatedChild<wxStaticText>(this, "GBCBiosLabel")));
|
||||
|
||||
for (size_t i = 0; i < kNbPalettes; i++) {
|
||||
// All of the wxPanel logic is handled in its client object.
|
||||
wxPanel* panel =
|
||||
GetValidatedChild<wxPanel>(this, wxString::Format("cp%zu", i));
|
||||
GBPalettePanelData* palette_data = new GBPalettePanelData(panel, i);
|
||||
|
||||
// `panel` takes ownership of `palette_data` here.
|
||||
panel->SetClientObject(palette_data);
|
||||
panel->SetValidator(PaletteValidator(palette_data));
|
||||
}
|
||||
|
||||
this->Fit();
|
||||
}
|
||||
|
||||
} // namespace dialogs
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef VBAM_WX_DIALOGS_GAME_BOY_CONFIG_H_
|
||||
#define VBAM_WX_DIALOGS_GAME_BOY_CONFIG_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <wx/clrpicker.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include "widgets/keep-on-top-styler.h"
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
// Manages the Game Boy configuration dialog.
|
||||
class GameBoyConfig : public wxDialog {
|
||||
public:
|
||||
static GameBoyConfig* NewInstance(wxWindow* parent);
|
||||
~GameBoyConfig() override = default;
|
||||
|
||||
private:
|
||||
// The constructor is private so initialization has to be done via the
|
||||
// static method. This is because this class is destroyed when its
|
||||
// owner, `parent` is destroyed. This prevents accidental deletion.
|
||||
GameBoyConfig(wxWindow* parent);
|
||||
|
||||
const widgets::KeepOnTopStyler keep_on_top_styler_;
|
||||
};
|
||||
|
||||
} // namespace dialogs
|
||||
|
||||
#endif // VBAM_WX_DIALOGS_GAME_BOY_CONFIG_H_
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef VBAM_WX_DIALOGS_VALIDATED_CHILD_H_
|
||||
#define VBAM_WX_DIALOGS_VALIDATED_CHILD_H_
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/window.h>
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
// Helper functions to assert on the returned value.
|
||||
inline wxWindow* GetValidatedChild(const wxWindow* parent,
|
||||
const wxString& name) {
|
||||
wxWindow* window = parent->FindWindow(name);
|
||||
assert(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T* GetValidatedChild(const wxWindow* parent, const wxString& name) {
|
||||
T* child = wxDynamicCast(GetValidatedChild(parent, name), T);
|
||||
assert(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
} // namespace dialogs
|
||||
|
||||
#endif // VBAM_WX_DIALOGS_VALIDATED_CHILD_H_
|
|
@ -29,6 +29,7 @@
|
|||
#include "config/option.h"
|
||||
#include "config/user-input.h"
|
||||
#include "dialogs/display-config.h"
|
||||
#include "dialogs/game-boy-config.h"
|
||||
#include "opts.h"
|
||||
#include "widgets/option-validator.h"
|
||||
|
||||
|
@ -1399,83 +1400,6 @@ wxString CheatListCtrl::OnGetItemText(long item, long column) const
|
|||
return s;
|
||||
}
|
||||
|
||||
// these are the choices for canned colors; their order must match the
|
||||
// names in the choice control
|
||||
static const uint16_t defaultPalettes[][8] = {
|
||||
{
|
||||
// Standard
|
||||
0x7FFF, 0x56B5, 0x318C, 0x0000, 0x7FFF, 0x56B5, 0x318C, 0x0000,
|
||||
},
|
||||
{
|
||||
// Blue Sea
|
||||
0x6200, 0x7E10, 0x7C10, 0x5000, 0x6200, 0x7E10, 0x7C10, 0x5000,
|
||||
},
|
||||
{
|
||||
// Dark Night
|
||||
0x4008, 0x4000, 0x2000, 0x2008, 0x4008, 0x4000, 0x2000, 0x2008,
|
||||
},
|
||||
{
|
||||
// Green Forest
|
||||
0x43F0, 0x03E0, 0x4200, 0x2200, 0x43F0, 0x03E0, 0x4200, 0x2200,
|
||||
},
|
||||
{
|
||||
// Hot Desert
|
||||
0x43FF, 0x03FF, 0x221F, 0x021F, 0x43FF, 0x03FF, 0x221F, 0x021F,
|
||||
},
|
||||
{
|
||||
// Pink Dreams
|
||||
0x621F, 0x7E1F, 0x7C1F, 0x2010, 0x621F, 0x7E1F, 0x7C1F, 0x2010,
|
||||
},
|
||||
{
|
||||
// Weird Colors
|
||||
0x621F, 0x401F, 0x001F, 0x2010, 0x621F, 0x401F, 0x001F, 0x2010,
|
||||
},
|
||||
{
|
||||
// Real GB Colors
|
||||
0x1B8E, 0x02C0, 0x0DA0, 0x1140, 0x1B8E, 0x02C0, 0x0DA0, 0x1140,
|
||||
},
|
||||
{
|
||||
// Real 'GB on GBASP' Colors
|
||||
0x7BDE, /*0x23F0*/ 0x5778, /*0x5DC0*/ 0x5640, 0x0000, 0x7BDE, /*0x3678*/ 0x529C, /*0x0980*/ 0x2990, 0x0000,
|
||||
}
|
||||
};
|
||||
|
||||
// manage the GB color prefs' canned color selecter
|
||||
static class GBColorConfig_t : public wxEvtHandler {
|
||||
public:
|
||||
wxWindow* p;
|
||||
wxChoice* c;
|
||||
wxColourPickerCtrl* cp[8];
|
||||
int pno;
|
||||
void ColorSel(wxCommandEvent& ev)
|
||||
{
|
||||
if (ev.GetSelection() > 0) {
|
||||
const uint16_t* color = defaultPalettes[ev.GetSelection() - 1];
|
||||
|
||||
for (int i = 0; i < 8; i++, color++)
|
||||
cp[i]->SetColour(wxColor(((*color << 3) & 0xf8),
|
||||
((*color >> 2) & 0xf8),
|
||||
((*color >> 7) & 0xf8)));
|
||||
}
|
||||
}
|
||||
void ColorReset(wxCommandEvent& ev)
|
||||
{
|
||||
(void)ev; // unused params
|
||||
const uint16_t* color = &systemGbPalette[pno * 8];
|
||||
|
||||
for (int i = 0; i < 8; i++, color++)
|
||||
cp[i]->SetColour(wxColor(((*color << 3) & 0xf8),
|
||||
((*color >> 2) & 0xf8),
|
||||
((*color >> 7) & 0xf8)));
|
||||
}
|
||||
|
||||
void ColorButton(wxCommandEvent& ev)
|
||||
{
|
||||
(void)ev; // unused params
|
||||
c->SetSelection(0);
|
||||
}
|
||||
} GBColorConfigHandler[3];
|
||||
|
||||
// disable controls if a GBA game is not loaded
|
||||
class GBACtrlEnabler : public wxValidator {
|
||||
public:
|
||||
|
@ -1701,85 +1625,6 @@ public:
|
|||
}
|
||||
} JoyPadConfigHandler[4];
|
||||
|
||||
// manage fullscreen mode widget
|
||||
// technically, it's more than a validator: it modifies the widget as well
|
||||
class ScreenModeList : public wxValidator {
|
||||
public:
|
||||
ScreenModeList()
|
||||
: wxValidator()
|
||||
{
|
||||
}
|
||||
ScreenModeList(const ScreenModeList& e)
|
||||
: wxValidator()
|
||||
{
|
||||
(void)e; // unused params
|
||||
}
|
||||
wxObject* Clone() const { return new ScreenModeList(*this); }
|
||||
bool Validate(wxWindow* p) {
|
||||
(void)p; // unused params
|
||||
return true;
|
||||
}
|
||||
bool TransferToWindow()
|
||||
{
|
||||
wxChoice* c = wxStaticCast(GetWindow(), wxChoice);
|
||||
wxDisplay d(wxDisplay::GetFromWindow(c->GetParent()));
|
||||
c->Clear();
|
||||
int modeno = 0, bestmode = 0;
|
||||
int bm_bpp = 0;
|
||||
c->Append(_("Desktop mode"));
|
||||
// probably ought to just disable this whole control on UNIX/X11 since
|
||||
// wxDisplay is so broken.
|
||||
vm = d.GetModes();
|
||||
wxString s;
|
||||
|
||||
for (size_t i = 0; i < vm.size(); i++) {
|
||||
s.Printf(_("%d x %d - %d bpp @ %d Hz"), vm[i].w, vm[i].h, vm[i].bpp, vm[i].refresh);
|
||||
c->Append(s);
|
||||
|
||||
if (!modeno && gopts.fs_mode.w == vm[i].w && gopts.fs_mode.h == vm[i].h) {
|
||||
if (gopts.fs_mode.bpp == vm[i].bpp && gopts.fs_mode.refresh == vm[i].refresh)
|
||||
modeno = i + 1;
|
||||
else if (vm[i].bpp == gopts.fs_mode.bpp && bm_bpp != gopts.fs_mode.bpp) {
|
||||
bestmode = i + 1;
|
||||
bm_bpp = vm[i].bpp;
|
||||
} else if (bm_bpp != gopts.fs_mode.bpp && bm_bpp != 32 && vm[i].bpp == 32) {
|
||||
bm_bpp = vm[i].bpp;
|
||||
bestmode = i + 1;
|
||||
} else if (bm_bpp != gopts.fs_mode.bpp && bm_bpp < 24 && vm[i].bpp == 24) {
|
||||
bm_bpp = vm[i].bpp;
|
||||
bestmode = i + 1;
|
||||
} else if (bm_bpp != gopts.fs_mode.bpp && bm_bpp < 24 && bm_bpp != 16 && vm[i].bpp == 16) {
|
||||
bm_bpp = vm[i].bpp;
|
||||
bestmode = i + 1;
|
||||
} else if (!bm_bpp) {
|
||||
bm_bpp = vm[i].bpp;
|
||||
bestmode = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!modeno && bestmode)
|
||||
modeno = bestmode;
|
||||
|
||||
c->SetSelection(modeno);
|
||||
return true;
|
||||
}
|
||||
bool TransferFromWindow()
|
||||
{
|
||||
int bestmode = wxStaticCast(GetWindow(), wxChoice)->GetSelection();
|
||||
|
||||
if (!bestmode)
|
||||
gopts.fs_mode.h = gopts.fs_mode.w = gopts.fs_mode.bpp = gopts.fs_mode.refresh = 0;
|
||||
else
|
||||
gopts.fs_mode = vm[bestmode - 1];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
wxArrayVideoModes vm;
|
||||
};
|
||||
|
||||
// this is the cmd table index for the accel tree ctrl
|
||||
// one of the "benefits" of using TreeItemData is that we have to
|
||||
// malloc them all, because treectrl destructor will free them all
|
||||
|
@ -2993,16 +2838,6 @@ bool MainFrame::BindControls()
|
|||
rb = SafeXRCCTRL<wxRadioButton>(d, n); \
|
||||
rb->SetValidator(wxBoolIntValidator(&o, v)); \
|
||||
} while (0)
|
||||
#define getrbb(n, o) \
|
||||
do { \
|
||||
rb = SafeXRCCTRL<wxRadioButton>(d, n); \
|
||||
rb->SetValidator(wxGenericValidator(&o)); \
|
||||
} while (0)
|
||||
#define getrbbr(n, o) \
|
||||
do { \
|
||||
rb = SafeXRCCTRL<wxRadioButton>(d, n); \
|
||||
rb->SetValidator(wxBoolRevValidator(&o)); \
|
||||
} while (0)
|
||||
wxBoolEnValidator* benval;
|
||||
wxBoolEnHandler* ben;
|
||||
#define getbe(n, o, cv, t, wt) \
|
||||
|
@ -3290,11 +3125,6 @@ bool MainFrame::BindControls()
|
|||
cb = SafeXRCCTRL<wxCheckBox>(d, n); \
|
||||
cb->SetValidator(wxGenericValidator(&o)); \
|
||||
} while (0)
|
||||
#define getcbi(n, o) \
|
||||
do { \
|
||||
cb = SafeXRCCTRL<wxCheckBox>(d, n); \
|
||||
cb->SetValidator(wxBoolIntValidator(&o, 1)); \
|
||||
} while (0)
|
||||
wxSpinCtrl* sc;
|
||||
#define getsc(n, o) \
|
||||
do { \
|
||||
|
@ -3357,106 +3187,14 @@ bool MainFrame::BindControls()
|
|||
}
|
||||
|
||||
d = LoadXRCDialog("UIConfig");
|
||||
{
|
||||
getcbb("HideMenuBar", gopts.hide_menu_bar);
|
||||
}
|
||||
#define getcbbe(n, o) getbe(n, o, cb, wxCheckBox, CB)
|
||||
wxBoolIntEnValidator* bienval;
|
||||
(void)bienval; // not used yet
|
||||
#define getbie(n, o, v, cv, t, wt) \
|
||||
do { \
|
||||
cv = SafeXRCCTRL<t>(d, n); \
|
||||
cv->SetValidator(wxBoolIntEnValidator(&o, v, v)); \
|
||||
bienval = wxStaticCast(cv->GetValidator(), wxBoolIntEnValidator); \
|
||||
static wxBoolEnHandler _ben; \
|
||||
ben = &_ben; \
|
||||
wx##wt##BoolEnHandlerConnect(cv, wxID_ANY, _ben); \
|
||||
} while (0)
|
||||
#define addbie(n) \
|
||||
do { \
|
||||
ben->controls.push_back(n); \
|
||||
bienval->controls.push_back(n); \
|
||||
} while (0)
|
||||
#define addbier(n, r) \
|
||||
do { \
|
||||
ben->controls.push_back(n); \
|
||||
ben->reverse.push_back(r); \
|
||||
bienval->controls.push_back(n); \
|
||||
bienval->reverse.push_back(r); \
|
||||
} while (0)
|
||||
#define getcbie(n, o, v) getbie(n, o, v, cb, wxCheckBox, CB)
|
||||
{ getcbb("HideMenuBar", gopts.hide_menu_bar); }
|
||||
wxFilePickerCtrl* fp;
|
||||
#define getfp(n, o, l) \
|
||||
do { \
|
||||
fp = SafeXRCCTRL<wxFilePickerCtrl>(d, n); \
|
||||
fp->SetValidator(wxFileDirPickerValidator(&o, l)); \
|
||||
} while (0)
|
||||
d = LoadXRCropertySheetDialog("GameBoyConfig");
|
||||
{
|
||||
/// System and Peripherals
|
||||
ch = GetValidatedChild<wxChoice, wxGenericValidator>(d, "System", wxGenericValidator(&gbEmulatorType));
|
||||
// "Display borders" corresponds to 2 variables, so it is handled
|
||||
// in command handler. Plus making changes might require resizing
|
||||
// game area. Validation only here.
|
||||
SafeXRCCTRL<wxChoice>(d, "Borders");
|
||||
/// GB Boot ROM
|
||||
wxStaticText *label = SafeXRCCTRL<wxStaticText>(d, "BiosFile");
|
||||
if (!gopts.gb_bios.empty()) label->SetLabel(gopts.gb_bios);
|
||||
getfp("BootRom", gopts.gb_bios, label);
|
||||
getlab("BootRomLab");
|
||||
/// GBC
|
||||
wxStaticText *clabel = SafeXRCCTRL<wxStaticText>(d, "CBiosFile");
|
||||
if (!gopts.gbc_bios.empty()) clabel->SetLabel(gopts.gbc_bios);
|
||||
getfp("CBootRom", gopts.gbc_bios, clabel);
|
||||
getlab("CBootRomLab");
|
||||
/// Custom Colors
|
||||
//getcbi("Color", gbColorOption);
|
||||
wxFarRadio* r = NULL;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
wxString pn;
|
||||
// NOTE: wx2.9.1 behaves differently for referenced nodes
|
||||
// than 2.8! Unless there is an actual child node, the ID field
|
||||
// will not be overwritten. This means that there should be a
|
||||
// dummy child node (e.g. position=(0,0)). If you get
|
||||
// "Unable to load dialog GameBoyConfig from resources", this is
|
||||
// probably the reason.
|
||||
pn.Printf(wxT("cp%d"), i + 1);
|
||||
wxWindow* w = SafeXRCCTRL<wxWindow>(d, pn);
|
||||
GBColorConfigHandler[i].p = w;
|
||||
GBColorConfigHandler[i].pno = i;
|
||||
wxFarRadio* cb = SafeXRCCTRL<wxFarRadio>(w, "UsePalette");
|
||||
|
||||
if (r)
|
||||
cb->SetGroup(r);
|
||||
else
|
||||
r = cb;
|
||||
|
||||
cb->SetValidator(wxBoolIntValidator(&gbPaletteOption, i));
|
||||
ch = SafeXRCCTRL<wxChoice>(w, "ColorSet");
|
||||
GBColorConfigHandler[i].c = ch;
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
wxString s;
|
||||
s.Printf(wxT("Color%d"), j);
|
||||
wxColourPickerCtrl* cp = SafeXRCCTRL<wxColourPickerCtrl>(w, s);
|
||||
GBColorConfigHandler[i].cp[j] = cp;
|
||||
cp->SetValidator(wxColorValidator(&systemGbPalette[i * 8 + j]));
|
||||
}
|
||||
|
||||
w->Connect(wxEVT_COMMAND_CHOICE_SELECTED,
|
||||
wxCommandEventHandler(GBColorConfig_t::ColorSel),
|
||||
NULL, &GBColorConfigHandler[i]);
|
||||
w->Connect(XRCID("Reset"), wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(GBColorConfig_t::ColorReset),
|
||||
NULL, &GBColorConfigHandler[i]);
|
||||
w->Connect(wxID_ANY, wxEVT_COMMAND_COLOURPICKER_CHANGED,
|
||||
wxCommandEventHandler(GBColorConfig_t::ColorButton),
|
||||
NULL, &GBColorConfigHandler[i]);
|
||||
}
|
||||
|
||||
d->Fit();
|
||||
}
|
||||
dialogs::GameBoyConfig::NewInstance(this);
|
||||
d = LoadXRCropertySheetDialog("GameBoyAdvanceConfig");
|
||||
{
|
||||
/// System and peripherals
|
||||
|
@ -3594,7 +3332,6 @@ bool MainFrame::BindControls()
|
|||
d->Fit();
|
||||
}
|
||||
wxDialog* joyDialog = LoadXRCropertySheetDialog("JoypadConfig");
|
||||
wxFarRadio* r = 0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
wxString pn;
|
||||
|
@ -3606,15 +3343,9 @@ bool MainFrame::BindControls()
|
|||
// probably the reason.
|
||||
pn.Printf(wxT("joy%d"), i + 1);
|
||||
wxWindow* w = SafeXRCCTRL<wxWindow>(joyDialog, pn);
|
||||
wxFarRadio* cb;
|
||||
cb = SafeXRCCTRL<wxFarRadio>(w, "DefaultConfig");
|
||||
|
||||
if (r)
|
||||
cb->SetGroup(r);
|
||||
else
|
||||
r = cb;
|
||||
|
||||
cb->SetValidator(wxBoolIntValidator(&gopts.default_stick, i + 1));
|
||||
w->FindWindow("DefaultConfig")
|
||||
->SetValidator(wxBoolIntValidator(&gopts.default_stick, i + 1));
|
||||
wxWindow *prev = NULL, *prevp = NULL;
|
||||
|
||||
for (const config::GameKey& game_key : config::kAllGameKeys) {
|
||||
|
|
|
@ -529,7 +529,7 @@ void load_opts(bool first_time_launch) {
|
|||
case config::Option::Type::kGbPalette: {
|
||||
wxString temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetGbPaletteString());
|
||||
opt.SetGbPalette(temp);
|
||||
opt.SetGbPaletteString(temp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -768,7 +768,7 @@ void opt_set(const wxString& name, const wxString& val) {
|
|||
opt->SetEnumString(val);
|
||||
return;
|
||||
case config::Option::Type::kGbPalette:
|
||||
opt->SetGbPalette(val);
|
||||
opt->SetGbPaletteString(val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,7 @@ extern struct opts_t {
|
|||
wxVideoMode fs_mode;
|
||||
|
||||
/// GB
|
||||
wxString gb_bios;
|
||||
bool gb_colorizer_hack = false;
|
||||
bool gb_lcd_filter = false;
|
||||
wxString gbc_bios;
|
||||
bool print_auto_page = true;
|
||||
bool print_screen_cap = false;
|
||||
wxString gb_rom_dir;
|
||||
|
|
|
@ -115,7 +115,15 @@ GameArea::GameArea()
|
|||
config::OptionID::kDispStretch},
|
||||
std::bind(&GameArea::ResetPanel, this)),
|
||||
scale_observer_(config::OptionID::kDispScale,
|
||||
std::bind(&GameArea::AdjustSize, this, true)) {
|
||||
std::bind(&GameArea::AdjustSize, this, true)),
|
||||
gb_border_observer_(
|
||||
config::OptionID::kPrefBorderOn,
|
||||
std::bind(&GameArea::OnGBBorderChanged, this, std::placeholders::_1)),
|
||||
gb_palette_observer_(
|
||||
{config::OptionID::kGBPalette0, config::OptionID::kGBPalette1,
|
||||
config::OptionID::kGBPalette2,
|
||||
config::OptionID::kPrefGBPaletteOption},
|
||||
std::bind(&gbResetPalette)) {
|
||||
SetSizer(new wxBoxSizer(wxVERTICAL));
|
||||
// all renderers prefer 32-bit
|
||||
// well, "simple" prefers 24-bit, but that's not available for filters
|
||||
|
@ -269,23 +277,21 @@ void GameArea::LoadGame(const wxString& name)
|
|||
// Set up the core for the colorizer hack.
|
||||
setColorizerHack(OPTION(kGBColorizerHack));
|
||||
|
||||
bool use_bios =
|
||||
const bool use_bios =
|
||||
gbCgbMode ? gopts.use_bios_file_gbc : gopts.use_bios_file_gb;
|
||||
|
||||
wxCharBuffer fnb(UTF8((gbCgbMode ? gopts.gbc_bios : gopts.gb_bios)));
|
||||
const char* fn = fnb.data();
|
||||
|
||||
gbCPUInit(fn, use_bios);
|
||||
const wxString bios_file = gbCgbMode ? OPTION(kGBGBCBiosFile).Get() : OPTION(kGBBiosFile).Get();
|
||||
gbCPUInit(bios_file.To8BitData().data(), use_bios);
|
||||
|
||||
if (use_bios && !coreOptions.useBios) {
|
||||
wxLogError(_("Could not load BIOS %s"), (gbCgbMode ? gopts.gbc_bios : gopts.gb_bios).mb_str());
|
||||
wxLogError(_("Could not load BIOS %s"), bios_file);
|
||||
// could clear use flag & file name now, but better to force
|
||||
// user to do it
|
||||
}
|
||||
|
||||
gbReset();
|
||||
|
||||
if (gbBorderOn) {
|
||||
if (OPTION(kPrefBorderOn)) {
|
||||
basic_width = gbBorderLineSkip = SGBWidth;
|
||||
basic_height = SGBHeight;
|
||||
gbBorderColumnSkip = (SGBWidth - GBWidth) / 2;
|
||||
|
@ -2629,3 +2635,14 @@ void GameArea::ShowMenuBar()
|
|||
menu_bar_hidden = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void GameArea::OnGBBorderChanged(config::Option* option) {
|
||||
if (game_type() == IMAGE_GB && gbSgbMode) {
|
||||
if (option->GetBool()) {
|
||||
AddBorder();
|
||||
gbSgbRenderBorder();
|
||||
} else {
|
||||
DelBorder();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
#include "widgets/group-check-box.h"
|
||||
|
||||
namespace widgets {
|
||||
|
||||
namespace {
|
||||
|
||||
wxWindow* FindTopLevelWindow(wxWindow* window) {
|
||||
while (window != nullptr && !window->IsTopLevel()) {
|
||||
window = window->GetParent();
|
||||
}
|
||||
assert(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
GroupCheckBox* FindGroupCheckBox(wxWindow* window,
|
||||
const wxString& name,
|
||||
GroupCheckBox* current) {
|
||||
if (window == current) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (window->IsKindOf(wxCLASSINFO(GroupCheckBox))) {
|
||||
GroupCheckBox* check_box = wxDynamicCast(window, GroupCheckBox);
|
||||
if (check_box->GetName() == name) {
|
||||
return check_box;
|
||||
}
|
||||
}
|
||||
|
||||
for (wxWindow* child : window->GetChildren()) {
|
||||
GroupCheckBox* check_box = FindGroupCheckBox(child, name, current);
|
||||
if (check_box) {
|
||||
return check_box;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern const char GroupCheckBoxNameStr[] = "groupcheck";
|
||||
|
||||
GroupCheckBox::GroupCheckBox() : wxCheckBox(), next_(this) {}
|
||||
|
||||
GroupCheckBox::GroupCheckBox(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxString& label,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style,
|
||||
const wxValidator& validator,
|
||||
const wxString& name)
|
||||
: next_(this) {
|
||||
Create(parent, id, label, pos, size, style, validator, name);
|
||||
}
|
||||
|
||||
GroupCheckBox::~GroupCheckBox() {
|
||||
RemoveFromGroup();
|
||||
}
|
||||
|
||||
bool GroupCheckBox::Create(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxString& label,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style,
|
||||
const wxValidator& validator,
|
||||
const wxString& name) {
|
||||
if (!wxCheckBox::Create(parent, id, label, pos, size, style, validator,
|
||||
name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AddToGroup();
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GroupCheckBox::AddToGroup() {
|
||||
assert(next_ == this);
|
||||
|
||||
if (GetName().IsEmpty()) {
|
||||
// No name means a singleton.
|
||||
return;
|
||||
}
|
||||
|
||||
// Find another GroupCheckBox with the same name as this.
|
||||
GroupCheckBox* other_box =
|
||||
FindGroupCheckBox(FindTopLevelWindow(this), GetName(), this);
|
||||
if (!other_box) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the previous GroupCheckBox to put this in the circular linked list.
|
||||
GroupCheckBox* prev_box = other_box;
|
||||
while (prev_box->next_ != other_box) {
|
||||
prev_box = prev_box->next_;
|
||||
}
|
||||
|
||||
next_ = other_box;
|
||||
prev_box->next_ = this;
|
||||
}
|
||||
|
||||
void GroupCheckBox::RemoveFromGroup() {
|
||||
GroupCheckBox* prev_box = this;
|
||||
while (prev_box->next_ != this) {
|
||||
prev_box = prev_box->next_;
|
||||
}
|
||||
|
||||
// Update the link.
|
||||
prev_box->next_ = next_;
|
||||
next_ = this;
|
||||
}
|
||||
|
||||
void GroupCheckBox::OnCheck(wxCommandEvent& event) {
|
||||
UpdateGroup();
|
||||
|
||||
// Let the event propagate.
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
void GroupCheckBox::UpdateGroup() {
|
||||
if (next_ == this) {
|
||||
// Nothing more to do if not part of a group.
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetValue()) {
|
||||
for (GroupCheckBox* check_box = next_; check_box != this;
|
||||
check_box = check_box->next_) {
|
||||
check_box->SetValue(false);
|
||||
}
|
||||
} else {
|
||||
// Find a checked GroupCheckBox.
|
||||
GroupCheckBox* check_box = next_;
|
||||
while (check_box != this) {
|
||||
if (check_box->GetValue()) {
|
||||
break;
|
||||
}
|
||||
check_box = check_box->next_;
|
||||
}
|
||||
|
||||
// Ensure at least one GroupCheckBox is checked.
|
||||
if (check_box == this) {
|
||||
SetValue(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCheckBox::SetValue(bool val) {
|
||||
wxCheckBox::SetValue(val);
|
||||
if (initialized_) {
|
||||
UpdateGroup();
|
||||
}
|
||||
}
|
||||
|
||||
void GroupCheckBox::SetName(const wxString& name) {
|
||||
wxCheckBox::SetName(name);
|
||||
if (initialized_) {
|
||||
RemoveFromGroup();
|
||||
AddToGroup();
|
||||
}
|
||||
}
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(GroupCheckBox, wxCheckBox);
|
||||
|
||||
// clang-format off
|
||||
wxBEGIN_EVENT_TABLE(GroupCheckBox, wxCheckBox)
|
||||
EVT_CHECKBOX(wxID_ANY, GroupCheckBox::OnCheck)
|
||||
wxEND_EVENT_TABLE();
|
||||
// clang-format on
|
||||
|
||||
GroupCheckBoxXmlHandler::GroupCheckBoxXmlHandler() : wxXmlResourceHandler() {
|
||||
AddWindowStyles();
|
||||
}
|
||||
|
||||
wxObject* GroupCheckBoxXmlHandler::DoCreateResource() {
|
||||
XRC_MAKE_INSTANCE(control, GroupCheckBox)
|
||||
|
||||
control->Create(m_parentAsWindow, GetID(), GetText("label"), GetPosition(),
|
||||
GetSize(), GetStyle(), wxDefaultValidator, GetName());
|
||||
|
||||
SetupWindow(control);
|
||||
|
||||
return control;
|
||||
}
|
||||
|
||||
bool GroupCheckBoxXmlHandler::CanHandle(wxXmlNode* node) {
|
||||
return IsOfClass(node, "GroupCheckBox");
|
||||
}
|
||||
|
||||
wxIMPLEMENT_DYNAMIC_CLASS(GroupCheckBoxXmlHandler, wxXmlResourceHandler);
|
||||
|
||||
} // namespace widgets
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef VBAM_WX_WIDGETS_GROUP_CHECK_BOX_H_
|
||||
#define VBAM_WX_WIDGETS_GROUP_CHECK_BOX_H_
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/xrc/xmlres.h>
|
||||
|
||||
namespace widgets {
|
||||
|
||||
extern const char GroupCheckBoxNameStr[];
|
||||
|
||||
// A custom check box that is part of a group where only one element can be
|
||||
// active at any given time. The other check boxes in the group are identified
|
||||
// as GroupCheckBoxes with the same name within the same top-level window.
|
||||
//
|
||||
// Internally, the other GroupCheckBoxes in the same group are tracked in a
|
||||
// circular linked list, via the `next_` pointer. On initialization, this links
|
||||
// to this object. The list is updated when the GroupCheckBox name is set or
|
||||
// reset.
|
||||
class GroupCheckBox : public wxCheckBox {
|
||||
public:
|
||||
GroupCheckBox();
|
||||
GroupCheckBox(
|
||||
wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxString& label,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0,
|
||||
const wxValidator& validator = wxDefaultValidator,
|
||||
const wxString& name = wxString::FromAscii(GroupCheckBoxNameStr));
|
||||
~GroupCheckBox() override;
|
||||
|
||||
bool Create(
|
||||
wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxString& label,
|
||||
const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize,
|
||||
long style = 0,
|
||||
const wxValidator& validator = wxDefaultValidator,
|
||||
const wxString& name = wxString::FromAscii(GroupCheckBoxNameStr));
|
||||
|
||||
// wxCheckBox implementation.
|
||||
void SetValue(bool val) override;
|
||||
void SetName(const wxString& name) override;
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(GroupCheckBox);
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
|
||||
private:
|
||||
void AddToGroup();
|
||||
void RemoveFromGroup();
|
||||
|
||||
void OnCheck(wxCommandEvent& event);
|
||||
|
||||
void UpdateGroup();
|
||||
|
||||
bool initialized_ = false;
|
||||
GroupCheckBox* next_;
|
||||
};
|
||||
|
||||
// Handler to load the resource from an XRC file as a "GroupCheckBox" object.
|
||||
class GroupCheckBoxXmlHandler : public wxXmlResourceHandler {
|
||||
public:
|
||||
GroupCheckBoxXmlHandler();
|
||||
~GroupCheckBoxXmlHandler() override = default;
|
||||
|
||||
wxObject* DoCreateResource() override;
|
||||
bool CanHandle(wxXmlNode* node) override;
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(wxCheckBoxXmlHandler);
|
||||
};
|
||||
|
||||
} // namespace widgets
|
||||
|
||||
#endif // VBAM_WX_WIDGETS_GROUP_CHECK_BOX_H_
|
|
@ -3,39 +3,11 @@
|
|||
// utility widgets
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/valgen.h>
|
||||
|
||||
using std::uint8_t;
|
||||
using std::uint16_t;
|
||||
using std::uint32_t;
|
||||
using std::int8_t;
|
||||
using std::int16_t;
|
||||
using std::int32_t;
|
||||
|
||||
// simple radio button not under the same parent window
|
||||
// note that it must be checkbox, as wx radio buttons have rigid behavior
|
||||
class wxFarRadio : public wxCheckBox {
|
||||
public:
|
||||
wxFarRadio();
|
||||
virtual ~wxFarRadio();
|
||||
void SetValue(bool val);
|
||||
// join this group with widget(s) in grp
|
||||
void SetGroup(class wxFarRadio* grp);
|
||||
// turn into a singleton
|
||||
void BreakGroup();
|
||||
// iterate over members in group (ring)
|
||||
wxFarRadio* GetNext();
|
||||
|
||||
protected:
|
||||
void UpdatedValue();
|
||||
void UpdateEvt(wxCommandEvent& ev);
|
||||
wxFarRadio* Next;
|
||||
DECLARE_DYNAMIC_CLASS(wxFarRadio)
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
// boolean copy-only validator that uses a constant int
|
||||
// may be attached to radio button or checkbox
|
||||
class wxBoolIntValidator : public wxValidator {
|
||||
|
@ -110,8 +82,6 @@ protected:
|
|||
bool* vptr;
|
||||
};
|
||||
|
||||
#include <wx/stattext.h>
|
||||
|
||||
// wxFilePickerCtrl/wxDirPickerCtrl copy-only vvalidator
|
||||
class wxFileDirPickerValidator : public wxValidator {
|
||||
public:
|
||||
|
@ -144,56 +114,10 @@ protected:
|
|||
wxStaticText* vlabel;
|
||||
};
|
||||
|
||||
// color copy-only validator that supports either 32-bit or 16-bit color
|
||||
// value (but not endianness..)
|
||||
// FIXME: only supported formats are RGB888 and BGR555
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class wxColorValidator : public wxValidator {
|
||||
public:
|
||||
wxColorValidator(uint32_t* vptr)
|
||||
: wxValidator()
|
||||
, ptr32(vptr)
|
||||
, ptr16(0)
|
||||
{
|
||||
}
|
||||
wxColorValidator(uint16_t* vptr)
|
||||
: wxValidator()
|
||||
, ptr32(0)
|
||||
, ptr16(vptr)
|
||||
{
|
||||
}
|
||||
wxColorValidator(const wxColorValidator& v)
|
||||
: wxValidator()
|
||||
, ptr32(v.ptr32)
|
||||
, ptr16(v.ptr16)
|
||||
{
|
||||
}
|
||||
wxObject* Clone() const
|
||||
{
|
||||
return new wxColorValidator(*this);
|
||||
}
|
||||
bool TransferToWindow();
|
||||
bool TransferFromWindow();
|
||||
bool Validate(wxWindow* p)
|
||||
{
|
||||
(void)p; // unused params
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
uint32_t* ptr32;
|
||||
uint16_t* ptr16;
|
||||
};
|
||||
|
||||
// Copy-only validators for checkboxes and radio buttons that enables a set
|
||||
// of dependent widgets
|
||||
// Requires an event handler during run-time
|
||||
|
||||
#include <vector>
|
||||
#include <wx/valgen.h>
|
||||
|
||||
// there's probably a standard wxWindowList or some such, but it's
|
||||
// undocumented and I prefer arrays
|
||||
typedef std::vector<wxWindow*> wxWindow_v;
|
||||
|
|
|
@ -8,108 +8,6 @@
|
|||
#include <wx/wx.h>
|
||||
#include <wx/spinctrl.h>
|
||||
|
||||
wxFarRadio::wxFarRadio()
|
||||
: wxCheckBox()
|
||||
{
|
||||
Next = this;
|
||||
}
|
||||
|
||||
wxFarRadio::~wxFarRadio()
|
||||
{
|
||||
BreakGroup();
|
||||
}
|
||||
|
||||
void wxFarRadio::SetValue(bool val)
|
||||
{
|
||||
wxCheckBox::SetValue(val);
|
||||
UpdatedValue();
|
||||
}
|
||||
|
||||
void wxFarRadio::SetGroup(class wxFarRadio* grp)
|
||||
{
|
||||
if (grp == this)
|
||||
return;
|
||||
|
||||
wxFarRadio* checked = GetValue() ? this : NULL;
|
||||
|
||||
for (wxFarRadio* gp = Next; gp != this; gp = gp->Next) {
|
||||
if (gp == grp)
|
||||
return;
|
||||
|
||||
if (gp->GetValue())
|
||||
checked = gp;
|
||||
}
|
||||
|
||||
wxFarRadio* link = Next;
|
||||
Next = grp;
|
||||
bool clear_checked = false;
|
||||
wxFarRadio* gp;
|
||||
|
||||
for (gp = grp; gp->Next != grp; gp = gp->Next) {
|
||||
if (checked && GetValue())
|
||||
clear_checked = true;
|
||||
}
|
||||
|
||||
gp->Next = link;
|
||||
|
||||
if (checked && gp->GetValue())
|
||||
clear_checked = true;
|
||||
|
||||
if (clear_checked)
|
||||
checked->SetValue(false);
|
||||
|
||||
int l;
|
||||
|
||||
for (l = 1, gp = Next; gp != this; gp = gp->Next, l++)
|
||||
;
|
||||
}
|
||||
|
||||
void wxFarRadio::BreakGroup()
|
||||
{
|
||||
wxFarRadio** gp;
|
||||
|
||||
for (gp = &Next; *gp != this; gp = &(*gp)->Next)
|
||||
;
|
||||
|
||||
*gp = Next;
|
||||
Next = this;
|
||||
}
|
||||
|
||||
wxFarRadio* wxFarRadio::GetNext()
|
||||
{
|
||||
return Next;
|
||||
}
|
||||
|
||||
void wxFarRadio::UpdatedValue()
|
||||
{
|
||||
if (!GetValue()) {
|
||||
wxFarRadio* gp;
|
||||
|
||||
// just like system wx, ensure at least one always checked
|
||||
for (gp = Next; gp != this; gp = gp->Next)
|
||||
if (gp->GetValue())
|
||||
break;
|
||||
|
||||
if (gp == this) {
|
||||
SetValue(true);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
for (wxFarRadio* gp = Next; gp != this; gp = gp->Next)
|
||||
gp->SetValue(false);
|
||||
}
|
||||
|
||||
void wxFarRadio::UpdateEvt(wxCommandEvent& ev)
|
||||
{
|
||||
UpdatedValue();
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxFarRadio, wxCheckBox);
|
||||
BEGIN_EVENT_TABLE(wxFarRadio, wxCheckBox)
|
||||
EVT_CHECKBOX(wxID_ANY, wxFarRadio::UpdateEvt)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
bool wxBoolIntValidator::TransferToWindow()
|
||||
{
|
||||
if (!vptr)
|
||||
|
@ -250,50 +148,6 @@ bool wxFileDirPickerValidator::TransferFromWindow()
|
|||
return false;
|
||||
}
|
||||
|
||||
#include <wx/clrpicker.h>
|
||||
|
||||
bool wxColorValidator::TransferToWindow()
|
||||
{
|
||||
if (!ptr32 && !ptr16)
|
||||
return false;
|
||||
|
||||
wxColourPickerCtrl* cp = wxDynamicCast(GetWindow(), wxColourPickerCtrl);
|
||||
|
||||
if (!cp)
|
||||
return false;
|
||||
|
||||
if (ptr32)
|
||||
cp->SetColour(wxColor(((*ptr32 >> 16) & 0xff),
|
||||
((*ptr32 >> 8) & 0xff),
|
||||
((*ptr32) & 0xff)));
|
||||
else
|
||||
cp->SetColour(wxColor(((*ptr16 << 3) & 0xf8),
|
||||
((*ptr16 >> 2) & 0xf8),
|
||||
((*ptr16 >> 7) & 0xf8)));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxColorValidator::TransferFromWindow()
|
||||
{
|
||||
if (!ptr32 && !ptr16)
|
||||
return false;
|
||||
|
||||
wxColourPickerCtrl* cp = wxDynamicCast(GetWindow(), wxColourPickerCtrl);
|
||||
|
||||
if (!cp)
|
||||
return false;
|
||||
|
||||
wxColor c = cp->GetColour();
|
||||
|
||||
if (ptr32)
|
||||
*ptr32 = ((c.Red() & 0xff) << 16) + ((c.Green() & 0xff) << 8) + ((c.Blue() & 0xff));
|
||||
else
|
||||
*ptr16 = ((c.Red() & 0xf8) >> 3) + ((c.Green() & 0xf8) << 2) + ((c.Blue() & 0xf8) << 7);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void enable(wxWindow_v controls, std::vector<int> reverse, bool en)
|
||||
{
|
||||
for (size_t i = 0; i < controls.size(); i++)
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "config/user-input.h"
|
||||
#include "strutils.h"
|
||||
#include "wayland.h"
|
||||
#include "widgets/group-check-box.h"
|
||||
|
||||
namespace {
|
||||
static const wxString kOldConfigFileName("vbam.conf");
|
||||
|
@ -294,6 +295,7 @@ bool wxvbamApp::OnInit() {
|
|||
// note: if linking statically, next 2 pull in lot of unused code
|
||||
// maybe in future if not wxSHARED, load only builtin-needed handlers
|
||||
xr->InitAllHandlers();
|
||||
xr->AddHandler(new widgets::GroupCheckBoxXmlHandler());
|
||||
wxInitAllImageHandlers();
|
||||
get_config_path(config_path);
|
||||
// first, load override xrcs
|
||||
|
|
|
@ -605,6 +605,7 @@ public:
|
|||
void HidePointer();
|
||||
void HideMenuBar();
|
||||
void ShowMenuBar();
|
||||
void OnGBBorderChanged(config::Option* option);
|
||||
|
||||
protected:
|
||||
void MouseEvent(wxMouseEvent&);
|
||||
|
@ -621,6 +622,8 @@ protected:
|
|||
private:
|
||||
config::OptionsObserver render_observer_;
|
||||
config::OptionsObserver scale_observer_;
|
||||
config::OptionsObserver gb_border_observer_;
|
||||
config::OptionsObserver gb_palette_observer_;
|
||||
};
|
||||
|
||||
// wxString version of OSD message
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
<object class="wxBoxSizer">
|
||||
<orient>wxVERTICAL</orient>
|
||||
<object class="sizeritem">
|
||||
<object class="wxChoice" name="ColorSet">
|
||||
<object class="wxChoice" name="DefaultPalette">
|
||||
<content>
|
||||
<item/>
|
||||
<item>Custom</item>
|
||||
<item>Standard</item>
|
||||
<item>Blue Sea</item>
|
||||
<item>Dark Night</item>
|
||||
|
@ -80,7 +80,7 @@
|
|||
<object class="sizeritem">
|
||||
<object class="wxBoxSizer">
|
||||
<object class="sizeritem">
|
||||
<object class="wxCheckBox" name="UsePalette" subclass="wxFarRadio">
|
||||
<object class="GroupCheckBox" name="UsePalette">
|
||||
<label>Use this palette</label>
|
||||
</object>
|
||||
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
|
||||
|
|
|
@ -87,7 +87,7 @@
|
|||
<border>5</border>
|
||||
</object>
|
||||
<object class="sizeritem">
|
||||
<object class="wxFilePickerCtrl" name="BootRom">
|
||||
<object class="wxFilePickerCtrl" name="GBBiosPicker">
|
||||
<message>Select a File</message>
|
||||
<wildcard>BIOS files (*.bin;*.rom)|*.bin;*.rom|All files|*</wildcard>
|
||||
<size>472,30</size>
|
||||
|
@ -109,7 +109,7 @@
|
|||
<border>5</border>
|
||||
</object>
|
||||
<object class="sizeritem">
|
||||
<object class="wxFilePickerCtrl" name="CBootRom">
|
||||
<object class="wxFilePickerCtrl" name="GBCBiosPicker">
|
||||
<message>Select a File</message>
|
||||
<wildcard>BIOS files (*.bin;*.rom)|*.bin;*.rom|All files|*</wildcard>
|
||||
<size>472,30</size>
|
||||
|
@ -134,7 +134,7 @@
|
|||
<border>5</border>
|
||||
</object>
|
||||
<object class="sizeritem">
|
||||
<object class="wxStaticText" name="BiosFile">
|
||||
<object class="wxStaticText" name="GBBiosLabel">
|
||||
<label>(None)</label>
|
||||
</object>
|
||||
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
|
||||
|
@ -155,7 +155,7 @@
|
|||
<border>5</border>
|
||||
</object>
|
||||
<object class="sizeritem">
|
||||
<object class="wxStaticText" name="CBiosFile">
|
||||
<object class="wxStaticText" name="GBCBiosLabel">
|
||||
<label>(None)</label>
|
||||
</object>
|
||||
<flag>wxALL|wxALIGN_CENTRE_VERTICAL</flag>
|
||||
|
@ -174,19 +174,19 @@
|
|||
<object class="sizeritem">
|
||||
<object class="wxNotebook">
|
||||
<object class="notebookpage">
|
||||
<object_ref name="cp1" ref="GBColorPrefPanel">
|
||||
<object_ref name="cp0" ref="GBColorPrefPanel">
|
||||
<pos>0,0</pos>
|
||||
</object_ref>
|
||||
<label>Default</label>
|
||||
</object>
|
||||
<object class="notebookpage">
|
||||
<object_ref name="cp2" ref="GBColorPrefPanel">
|
||||
<object_ref name="cp1" ref="GBColorPrefPanel">
|
||||
<pos>0,0</pos>
|
||||
</object_ref>
|
||||
<label>User 1</label>
|
||||
</object>
|
||||
<object class="notebookpage">
|
||||
<object_ref name="cp3" ref="GBColorPrefPanel">
|
||||
<object_ref name="cp2" ref="GBColorPrefPanel">
|
||||
<pos>0,0</pos>
|
||||
</object_ref>
|
||||
<label>User 2</label>
|
||||
|
|
|
@ -511,7 +511,7 @@
|
|||
<flag>wxEXPAND|wxALL</flag>
|
||||
</object>
|
||||
<object class="sizeritem">
|
||||
<object class="wxCheckBox" name="DefaultConfig" subclass="wxFarRadio">
|
||||
<object class="GroupCheckBox" name="DefaultConfig">
|
||||
<label>Use as default</label>
|
||||
</object>
|
||||
</object>
|
||||
|
|
Loading…
Reference in New Issue