/***************************************************************************

  M.A.M.E.32  -  Multiple Arcade Machine Emulator for Win32
  Win32 Portions Copyright (C) 1997-2001 Michael Soderstrom and Chris Kirmse

  This file is part of MAME32, and may only be used, modified and
  distributed under the terms of the MAME license, in "readme.txt".
  By continuing to use, modify or distribute this file you indicate
  that you have read the license and understand and accept it fully.

***************************************************************************/
 
/***************************************************************************

  Properties.c

    Properties Popup and Misc UI support routines.
    
    Created 8/29/98 by Mike Haaland (mhaaland@hypertech.com)

***************************************************************************/

#define WIN32_LEAN_AND_MEAN
#define NONAMELESSUNION 1
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <commdlg.h>
#undef NONAMELESSUNION
#include <ddraw.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>

#include <driver.h>
#include <info.h>
#include "audit32.h"
#include "options.h"
#include "file.h"
#ifdef BUILD_ENGLISH
#include "resrce.h"
#else
#include "resrcj.h"
#endif
#include "DIJoystick.h"     /* For DIJoystick avalibility. */
#include "m32util.h"
#include "directdraw.h"
#include "properties.h"

#include "Mame32.h"
#include "DataMap.h"
#include "win32text.h"
#include "tsv.h"

/***************************************************************
 * Imported function prototypes
 ***************************************************************/

extern BOOL GameUsesTrackball(int game);
extern BOOL GameUsesRomPatch(int game);
extern int load_driver_history(const struct GameDriver *drv, char *buffer, int bufsize);

/**************************************************************
 * Local function prototypes
 **************************************************************/

static INT_PTR CALLBACK GamePropertiesDialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK GameOptionsProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK GameDisplayOptionsProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam);

static void SetStereoEnabled(HWND hWnd, int nIndex);
static void InitializeOptions(HWND hDlg);
static void InitializeMisc(HWND hDlg);
static void OptOnHScroll(HWND hWnd, HWND hwndCtl, UINT code, int pos);
static void GammaSelectionChange(HWND hwnd);
static void BrightCorrectSelectionChange(HWND hwnd);
static void BrightnessSelectionChange(HWND hwnd);
static void A2DSelectionChange(HWND hwnd);
static void ResDepthSelectionChange(HWND hWnd, HWND hWndCtrl);
static void RefreshSelectionChange(HWND hWnd, HWND hWndCtrl);
static void VolumeSelectionChange(HWND hwnd);
static void TransparentChange(HWND hwnd);
static void DSoundBufferSelectionChange(HWND hwnd);
static void RandomPlayTimeSelectionChange(HWND hwnd);
static void RotationChange(HWND hwnd);
static void ZoomxChange(HWND hwnd);
static void ZoomyChange(HWND hwnd);
static void UpdateDisplayModeUI(HWND hwnd, DWORD dwDepth, DWORD dwRefresh);
static void InitializeDisplayModeUI(HWND hwnd);
static void InitializeSoundUI(HWND hwnd);
static void InitializeSkippingUI(HWND hwnd);
static void InitializeRotateUI(HWND hwnd);
static void InitializeResDepthUI(HWND hwnd);
static void InitializeRefreshUI(HWND hwnd);
static void InitializeDefaultInputUI(HWND hWnd);
static void InitializeEffectUI(HWND hWnd);
static void InitializeBiosUI(HWND hWnd);
static void InitializeWindowSizeUI(HWND hWnd);
static void InitializeJoyidUI(HWND hWnd);
static void PropToOptions(HWND hWnd, options_type *o);
static void OptionsToProp(HWND hWnd, options_type *o);
static void SetPropEnabledControls(HWND hWnd);

static void BuildDataMap(void);
static void ResetDataMap(void);

static void HistoryFixBuf(char *buf);

/**************************************************************
 * Local private variables
 **************************************************************/

static options_type  origGameOpts;
static options_type* pGameOpts = NULL;

static int  g_nGame               = 0;
static BOOL g_bInternalSet        = FALSE;
static BOOL g_bUseDefaults        = FALSE;
static BOOL g_bReset              = FALSE;
static int  g_nSampleRateIndex    = 0;
static int  g_nVolumeIndex        = 0;
static int  g_nBrightCorrectIndex = 0;
static int  g_nGammaIndex         = 0;
static int  g_nRotateIndex        = 0;
static int  g_nInputIndex         = 0;
static int  g_nBrightnessIndex    = 0;
static int  g_nEffectIndex        = 0;
static int  g_nZoomxIndex         = 0;
static int  g_nZoomyIndex         = 0;
static int  g_nA2DIndex           = 0;

/* Game history variables */
#define MAX_HISTORY_LEN     (8 * 1024)

static char   historyBuf[MAX_HISTORY_LEN];
static char   tempHistoryBuf[MAX_HISTORY_LEN];

/* Property sheets */
static DWORD dwDlgId[] =
{
	IDD_PROP_GAME,
	IDD_PROP_AUDIT,
	IDD_PROP_DISPLAY,
	IDD_PROP_RENDER,
	IDD_PROP_ADVANCED,
	IDD_PROP_SOUND,
	IDD_PROP_INPUT,
	IDD_PROP_MISC
};

#define NUM_PROPSHEETS (sizeof(dwDlgId) / sizeof(dwDlgId[0]))

static struct ComboBoxEffect
{
	const char* m_pData;
} g_ComboBoxEffect[] = 
{
	{ "none"    },
	{ "scan25"  },
	{ "scan50"  },
	{ "scan75"  },
	{ "scan75v" },
	{ "rgb16"   },
	{ "rgb6"    },
	{ "rgb4"    },
	{ "rgb4v"   },
	{ "rgb3"    },
	{ "rgbtiny" },
	{ "sharp"   }
};

#define NUMEFFECTS (sizeof(g_ComboBoxEffect) / sizeof(g_ComboBoxEffect[0]))

/***************************************************************
 * Public functions
 ***************************************************************/

/* Checks of all ROMs are available for 'game' and returns result
 * Returns TRUE if all ROMs found, 0 if any ROMs are missing.
 */
BOOL FindRomSet(int game)
{
	const struct RomModule	*region, *rom;
	const struct GameDriver *gamedrv;
	const char				*name;
	int 					err;
	unsigned int			length, icrc;

	gamedrv = drivers[game];
 
	if (!osd_faccess(gamedrv->name, OSD_FILETYPE_ROM))
	{
		/* if the game is a clone, try loading the ROM from the main version */
		if (gamedrv->clone_of == 0
		||	(gamedrv->clone_of->flags & NOT_A_DRIVER)
		||	!osd_faccess(gamedrv->clone_of->name, OSD_FILETYPE_ROM))
			return FALSE;
	}

	/* loop over regions, then over files */
	for (region = rom_first_region(gamedrv); region; region = rom_next_region(region))
	{
		for (rom = rom_first_file(region); rom; rom = rom_next_file(rom))
		{
			extern struct GameDriver driver_0;
			const struct GameDriver *drv;

			name = ROM_GETNAME(rom);
			icrc = ROM_GETCRC(rom);
			length = 0;

			/* obtain CRC-32 and length of ROM file */
			drv = gamedrv;
			do
			{
				err = osd_fchecksum(drv->name, name, &length, &icrc);
				drv = drv->clone_of;
			}
			while (err && drv && drv != &driver_0);

			if (err)
				return FALSE;
		}
	}

	return TRUE;
}

void InitDefaultPropertyPage(HINSTANCE hInst, HWND hWnd)
{
	PROPSHEETHEADER pshead;
	PROPSHEETPAGE   pspage[NUM_PROPSHEETS];
	int             i;
	int             maxPropSheets;

	g_nGame = -1;
	maxPropSheets = NUM_PROPSHEETS - 2;

	/* Get default options to populate property sheets */
	pGameOpts = GetDefaultOptions();
	g_bUseDefaults = FALSE;
	/* Stash the result for comparing later */
	memcpy(&origGameOpts, pGameOpts, sizeof(options_type));
	g_bReset = FALSE;
	BuildDataMap();

	ZeroMemory(&pshead, sizeof(PROPSHEETHEADER));
	ZeroMemory(pspage, sizeof(PROPSHEETPAGE) * maxPropSheets);

	/* Fill in the property sheet header */
	pshead.hwndParent                 = hWnd;
	pshead.dwSize                     = sizeof(PROPSHEETHEADER);
	pshead.dwFlags                    = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_PROPTITLE;
	pshead.hInstance                  = hInst;
	pshead.pszCaption                 = win32_getstring(WIN32_property_defaultgame);
	pshead.nPages                     = maxPropSheets;
	pshead.DUMMYUNIONNAME2.nStartPage = 0;
	pshead.DUMMYUNIONNAME.pszIcon     = MAKEINTRESOURCE(IDI_MAME32_ICON);
	pshead.DUMMYUNIONNAME3.ppsp       = pspage;

	/* Fill out the property page templates */
	for (i = 0; i < maxPropSheets; i++)
	{
		pspage[i].dwSize                     = sizeof(PROPSHEETPAGE);
		pspage[i].dwFlags                    = 0;
		pspage[i].hInstance                  = hInst;
		pspage[i].DUMMYUNIONNAME.pszTemplate = MAKEINTRESOURCE(dwDlgId[i + 2]);
		pspage[i].pfnCallback                = NULL;
		pspage[i].lParam                     = 0;
		pspage[i].pfnDlgProc                 = GameOptionsProc;
	}
	pspage[2 - 2].pfnDlgProc = GameDisplayOptionsProc;

	/* Create the Property sheet and display it */
	if (PropertySheet(&pshead) == -1)
	{
		char temp[100];
		DWORD dwError = GetLastError();
		sprintf(temp, win32_getstring(WIN32_property_sheeterror), (int)dwError, (int)dwError);
		MessageBox(0, temp, win32_getstring(WIN32_property_sheeterrortitle), IDOK);
	}
}

void InitPropertyPage(HINSTANCE hInst, HWND hWnd, int game_num)
{
	InitPropertyPageToPage(hInst, hWnd, game_num, PROPERTIES_PAGE);
}

void InitPropertyPageToPage(HINSTANCE hInst, HWND hWnd, int game_num, int start_page)
{
	PROPSHEETHEADER pshead;
	PROPSHEETPAGE   pspage[NUM_PROPSHEETS];
	int             i;
	int             maxPropSheets;
    struct InternalMachineDriver drv;
    expand_machine_driver(drivers[game_num]->drv,&drv);

	InitGameAudit(game_num);
	g_nGame = game_num;
	maxPropSheets = NUM_PROPSHEETS;

	/* Get Game options to populate property sheets */
	pGameOpts = GetGameOptions(game_num);
	g_bUseDefaults = pGameOpts->use_default;
	/* Stash the result for comparing later */
	memcpy(&origGameOpts, pGameOpts, sizeof(options_type));
	g_bReset = FALSE;
	BuildDataMap();

	ZeroMemory(&pshead, sizeof(PROPSHEETHEADER));
	ZeroMemory(pspage, sizeof(PROPSHEETPAGE) * maxPropSheets);

	/* Fill in the property sheet header */
	pshead.hwndParent                 = hWnd;
	pshead.dwSize                     = sizeof(PROPSHEETHEADER);
	pshead.dwFlags                    = PSH_PROPSHEETPAGE | PSH_USEICONID | PSH_PROPTITLE;
	pshead.hInstance                  = hInst;
	pshead.pszCaption                 = GetDescriptionByIndex(g_nGame, UseJapaneseList());
	pshead.nPages                     = maxPropSheets;
	pshead.DUMMYUNIONNAME2.nStartPage = start_page;
	pshead.DUMMYUNIONNAME.pszIcon     = MAKEINTRESOURCE(IDI_MAME32_ICON);
	pshead.DUMMYUNIONNAME3.ppsp       = pspage;

	/* Fill out the property page templates */
	for (i = 0; i < maxPropSheets; i++)
	{
		pspage[i].dwSize                     = sizeof(PROPSHEETPAGE);
		pspage[i].dwFlags                    = 0;
		pspage[i].hInstance                  = hInst;
		pspage[i].DUMMYUNIONNAME.pszTemplate = MAKEINTRESOURCE(dwDlgId[i]);
		pspage[i].pfnCallback                = NULL;
		pspage[i].lParam                     = 0;
	}

	pspage[0].pfnDlgProc = GamePropertiesDialogProc;
	pspage[1].pfnDlgProc = GameAuditDialogProc;

	pspage[2].pfnDlgProc = GameDisplayOptionsProc;
	pspage[3].pfnDlgProc = GameOptionsProc;
	pspage[4].pfnDlgProc = GameOptionsProc;
	pspage[5].pfnDlgProc = GameOptionsProc;
	pspage[6].pfnDlgProc = GameOptionsProc;
	pspage[7].pfnDlgProc = GameOptionsProc;
	
	/* Create the Property sheet and display it */
	if (PropertySheet(&pshead) == -1)
	{
		char temp[100];
		DWORD dwError = GetLastError();
		sprintf(temp, win32_getstring(WIN32_property_sheeterror), (int)dwError, (int)dwError);
		MessageBox(0, temp, win32_getstring(WIN32_property_sheeterrortitle), IDOK);
	}
}

/*********************************************************************
 * Local Functions
 *********************************************************************/

/* Build CPU info string */
static char *GameInfoCPU(UINT nIndex)
{
	int i;
	static char buf[1024] = "";
    struct InternalMachineDriver drv;
    expand_machine_driver(drivers[nIndex]->drv,&drv);

	ZeroMemory(buf, sizeof(buf));
	i = 0;
	while (i < MAX_CPU && drv.cpu[i].cpu_type)
	{
		if (drv.cpu[i].cpu_clock >= 1000000)
			sprintf(&buf[strlen(buf)], "%s %d.%06d MHz",
					cputype_name(drv.cpu[i].cpu_type),
					drv.cpu[i].cpu_clock / 1000000,
					drv.cpu[i].cpu_clock % 1000000);
		else
			sprintf(&buf[strlen(buf)], "%s %d.%03d kHz",
					cputype_name(drv.cpu[i].cpu_type),
					drv.cpu[i].cpu_clock / 1000,
					drv.cpu[i].cpu_clock % 1000);

		if (drv.cpu[i].cpu_type & CPU_AUDIO_CPU)
			strcat(buf, win32_getstring(WIN32_property_sound));

		strcat(buf, "\n");

		i++;
    }

	return buf;
}

/* Build Sound system info string */
static char *GameInfoSound(UINT nIndex)
{
	int i;
	static char buf[1024] = "";
    struct InternalMachineDriver drv;
    expand_machine_driver(drivers[nIndex]->drv,&drv);

	ZeroMemory(buf, sizeof(buf));
	i = 0;
	while (i < MAX_SOUND && drv.sound[i].sound_type)
	{
		if (1 < sound_num(&drv.sound[i]))
			sprintf(&buf[strlen(buf)], "%d x ", sound_num(&drv.sound[i]));

		sprintf(&buf[strlen(buf)], "%s", sound_name(&drv.sound[i]));

		if (sound_clock(&drv.sound[i]))
		{
			if (sound_clock(&drv.sound[i]) >= 1000000)
				sprintf(&buf[strlen(buf)], " %d.%06d MHz",
						sound_clock(&drv.sound[i]) / 1000000,
						sound_clock(&drv.sound[i]) % 1000000);
			else
				sprintf(&buf[strlen(buf)], " %d.%03d kHz",
						sound_clock(&drv.sound[i]) / 1000,
						sound_clock(&drv.sound[i]) % 1000);
		}

		strcat(buf,"\n");

		i++;
	}
	return buf;
}

/* Build Display info string */
static char *GameInfoScreen(UINT nIndex)
{
	static char buf[1024];
    struct InternalMachineDriver drv;
    expand_machine_driver(drivers[nIndex]->drv,&drv);

	if (drivers[nIndex]->flags & ORIENTATION_SWAP_XY)
		sprintf(buf,win32_getstring(WIN32_property_verthz),
				drv.default_visible_area.max_y - drv.default_visible_area.min_y + 1,
				drv.default_visible_area.max_x - drv.default_visible_area.min_x + 1,
				drv.frames_per_second);
	else
		sprintf(buf,win32_getstring(WIN32_property_horzhz),
				drv.default_visible_area.max_x - drv.default_visible_area.min_x + 1,
				drv.default_visible_area.max_y - drv.default_visible_area.min_y + 1,
				drv.frames_per_second);

	return buf;
}

/* Build color information string */
static char *GameInfoColors(UINT nIndex)
{
	static char buf[1024];
    struct InternalMachineDriver drv;
    expand_machine_driver(drivers[nIndex]->drv,&drv);

	ZeroMemory(buf, sizeof(buf));

	sprintf(buf, win32_getstring(WIN32_property_colors), drv.total_colors);

	return buf;
}

/* Build game status string */
char *GameInfoStatus(UINT nIndex)
{
	switch (GetHasRoms(nIndex))
	{
	case 0:
		return (char *)win32_getstring(WIN32_property_rommissing);

	case 1:
		if (drivers[nIndex]->flags & GAME_BROKEN)
			return (char *)win32_getstring(WIN32_property_notworking);
		if (drivers[nIndex]->flags & GAME_WRONG_COLORS)
			return (char *)win32_getstring(WIN32_property_colorwrong);
		if (drivers[nIndex]->flags & GAME_IMPERFECT_COLORS)
			return (char *)win32_getstring(WIN32_property_imperfectcolor);
		else
			return (char *)win32_getstring(WIN32_property_working);

	default:
	case 2:
		return (char *)win32_getstring(WIN32_property_unknown);
	}
}

/* Build game manufacturer string */
static char *GameInfoManufactured(UINT nIndex)
{
	static char buf[1024];

	sprintf(buf, "%s %s", drivers[nIndex]->year, drivers[nIndex]->manufacturer); 
	return buf;
}

/* Build Game title string */
char *GameInfoTitle(UINT nIndex)
{
	static char buf[1024];

	if (nIndex == -1)
		strcpy(buf, win32_getstring(WIN32_property_globaloptions));
	else
		sprintf(buf, "%s\n\"%s\"", GetDescriptionByIndex(nIndex, UseJapaneseList()), drivers[nIndex]->name);
	return buf;
}

/* Build game clone infromation string */
static char *GameInfoCloneOf(UINT nIndex)
{
	static char buf[1024];

	buf[0] = '\0';

	if (drivers[nIndex]->clone_of != 0
	&&  !(drivers[nIndex]->clone_of->flags & NOT_A_DRIVER))
	{
		sprintf(buf, "%s - \"%s\"",
#ifdef BUILD_ENGLISH
				ConvertAmpersandString(ModifyThe(drivers[nIndex]->clone_of->description)),
#else
				ConvertAmpersandString(GetDescriptionByName(drivers[nIndex]->clone_of->name, UseJapaneseList())),
#endif
				drivers[nIndex]->clone_of->name); 
	}

	return buf;
}

/* Handle the information property page */
static INT_PTR CALLBACK GamePropertiesDialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
	case WM_INITDIALOG:
#if defined(USE_SINGLELINE_TABCONTROL)
		{
			HWND hWnd = PropSheet_GetTabControl(GetParent(hDlg));
			DWORD tabStyle = (GetWindowLong(hWnd,GWL_STYLE) & ~TCS_MULTILINE);
			SetWindowLong(hWnd,GWL_STYLE,tabStyle | TCS_SINGLELINE);
		}
#endif

		Static_SetText(GetDlgItem(hDlg, IDC_PROP_TITLE),         GameInfoTitle(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_MANUFACTURED),  GameInfoManufactured(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_STATUS),        GameInfoStatus(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_CPU),           GameInfoCPU(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_SOUND),         GameInfoSound(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_SCREEN),        GameInfoScreen(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_COLORS),        GameInfoColors(g_nGame));
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_CLONEOF),       GameInfoCloneOf(g_nGame));
		if (drivers[g_nGame]->clone_of != 0
		&& !(drivers[g_nGame]->clone_of->flags & NOT_A_DRIVER))
		{
			ShowWindow(GetDlgItem(hDlg, IDC_PROP_CLONEOF_TEXT), SW_SHOW);
		}
		else
		{
			ShowWindow(GetDlgItem(hDlg, IDC_PROP_CLONEOF_TEXT), SW_HIDE);
		}

		ShowWindow(hDlg, SW_SHOW);
		return 1;
	}
    return 0;
}

static BOOL ReadSkipCtrl(HWND hWnd, UINT nCtrlID, int *value)
{
	HWND hCtrl;
	char buf[100];
	int  nValue = *value;

	hCtrl = GetDlgItem(hWnd, nCtrlID);
	if (hCtrl)
	{
		/* Skip lines control */
		Edit_GetText(hCtrl, buf, 100);
		if (sscanf(buf, "%d", value) != 1)
			*value = 0;
	}

	return (nValue == *value) ? FALSE : TRUE;
}

/* Handle all options property pages */
static INT_PTR CALLBACK GameOptionsProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
	case WM_INITDIALOG:
		/* Fill in the Game info at the top of the sheet */
		Static_SetText(GetDlgItem(hDlg, IDC_PROP_TITLE), GameInfoTitle(g_nGame));
		InitializeOptions(hDlg);
		InitializeMisc(hDlg);

		PopulateControls(hDlg);
		OptionsToProp(hDlg, pGameOpts);
		SetPropEnabledControls(hDlg);
		if (g_nGame == -1)
			ShowWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), SW_HIDE);
		else
			EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), (g_bUseDefaults) ? FALSE : TRUE);

		EnableWindow(GetDlgItem(hDlg, IDC_PROP_RESET), g_bReset);
		ShowWindow(hDlg, SW_SHOW);
    
		return 1;

	case WM_HSCROLL:
		/* slider changed */
		HANDLE_WM_HSCROLL(hDlg, wParam, lParam, OptOnHScroll);
		g_bUseDefaults = FALSE;
		g_bReset = TRUE;
		EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), TRUE);
		PropSheet_Changed(GetParent(hDlg), hDlg);
		break;

	case WM_COMMAND:
		{
			/* Below, 'changed' is used to signify the 'Apply'
			 * button should be enabled.
			 */
			WORD wID         = GET_WM_COMMAND_ID(wParam, lParam);
			HWND hWndCtrl    = GET_WM_COMMAND_HWND(wParam, lParam);
			WORD wNotifyCode = GET_WM_COMMAND_CMD(wParam, lParam);
			BOOL changed     = FALSE;

			switch (wID)
			{
			case IDC_SIZES:
			case IDC_FRAMESKIP:
			case IDC_EFFECT:
			case IDC_DEFAULT_INPUT:
			case IDC_ROTATE:
			case IDC_SAMPLERATE:
			case IDC_BIOSTYPE:
			case IDC_WINDOWSIZE:
			case IDC_JOYID1:
			case IDC_JOYID2:
			case IDC_JOYID3:
			case IDC_JOYID4:
				if (wNotifyCode == CBN_SELCHANGE)
					changed = TRUE;
				break;

			case IDC_RESDEPTH:
				if (wNotifyCode == LBN_SELCHANGE)
				{
					ResDepthSelectionChange(hDlg, hWndCtrl);
					changed = TRUE;
				}
				break;

			case IDC_REFRESH:
				if (wNotifyCode == LBN_SELCHANGE)
				{
					RefreshSelectionChange(hDlg, hWndCtrl);
					changed = TRUE;
				}
				break;

			case IDC_ASPECTRATION:
			case IDC_ASPECTRATIOD:
			case IDC_KEYSTONERATIOU:
			case IDC_KEYSTONERATIOD:
				if (wNotifyCode == EN_CHANGE)
				{
					if (g_bInternalSet == FALSE)
						changed = TRUE;
				}
				break;

			case IDC_WINDOWED:
			case IDC_TRIPLE_BUFFER:
			case IDC_PATCH_ROMS:
				changed = ReadControl(hDlg, wID);
				break;

			case IDC_PROP_RESET:
				if (wNotifyCode != BN_CLICKED)
					break;

				memcpy(pGameOpts, &origGameOpts, sizeof(options_type));
				BuildDataMap();
				PopulateControls(hDlg);
				OptionsToProp(hDlg, pGameOpts);
				SetPropEnabledControls(hDlg);
				g_bReset = FALSE;
				PropSheet_UnChanged(GetParent(hDlg), hDlg);
				g_bUseDefaults = pGameOpts->use_default;
				EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), (g_bUseDefaults) ? FALSE : TRUE);
				break;

			case IDC_USE_DEFAULT:
				if (g_nGame != -1)
				{
					pGameOpts->use_default = TRUE;
					pGameOpts = GetGameOptions(g_nGame);
					g_bUseDefaults = pGameOpts->use_default;
					BuildDataMap();
					PopulateControls(hDlg);
					OptionsToProp(hDlg, pGameOpts);
					SetPropEnabledControls(hDlg);
					if (origGameOpts.use_default != g_bUseDefaults)
					{
						PropSheet_Changed(GetParent(hDlg), hDlg);
						g_bReset = TRUE;
					}
					else
					{
						PropSheet_UnChanged(GetParent(hDlg), hDlg);
						g_bReset = FALSE;
					}
					EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), (g_bUseDefaults) ? FALSE : TRUE);
				}
            
				break;

			default:
				if (wNotifyCode == BN_CLICKED)
				{
					switch (wID)
					{
					case IDC_SCANLINES:
						if (Button_GetCheck(GetDlgItem(hDlg, IDC_SCANLINES)))
						{
							Button_SetCheck(GetDlgItem(hDlg, IDC_VSCANLINES), FALSE);
						}
						break;

					case IDC_VSCANLINES:
						if (Button_GetCheck(GetDlgItem(hDlg, IDC_VSCANLINES)))
						{
							Button_SetCheck(GetDlgItem(hDlg, IDC_SCANLINES), FALSE);
						}
						break;
					}
					changed = TRUE;
				}
			}
        
			/* Enable the apply button */
			if (changed == TRUE)
			{
				pGameOpts->use_default = g_bUseDefaults = FALSE;
				PropSheet_Changed(GetParent(hDlg), hDlg);
				g_bReset = TRUE;
				EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), (g_bUseDefaults) ? FALSE : TRUE);
			}
			SetPropEnabledControls(hDlg);
		}
		break;

	case WM_NOTIFY:
		switch (((NMHDR *) lParam)->code)
		{
		case PSN_SETACTIVE:
			/* Initialize the controls. */
			PopulateControls(hDlg);
			OptionsToProp(hDlg, pGameOpts);
			SetPropEnabledControls(hDlg);
			EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), (g_bUseDefaults) ? FALSE : TRUE);
			break;

		case PSN_APPLY:
			/* Save and apply the options here */
			PropToOptions(hDlg, pGameOpts);
			ReadControls(hDlg);
			pGameOpts->use_default = g_bUseDefaults;
			if (g_nGame == -1)
				pGameOpts = GetDefaultOptions();
			else
				pGameOpts = GetGameOptions(g_nGame);

			memcpy(&origGameOpts, pGameOpts, sizeof(options_type));
			BuildDataMap();
			PopulateControls(hDlg);
			OptionsToProp(hDlg, pGameOpts);
			SetPropEnabledControls(hDlg);
			EnableWindow(GetDlgItem(hDlg, IDC_USE_DEFAULT), (g_bUseDefaults) ? FALSE : TRUE);
			g_bReset = FALSE;
			PropSheet_UnChanged(GetParent(hDlg), hDlg);
			SetWindowLong(hDlg, DWL_MSGRESULT, TRUE);
			break;

		case PSN_KILLACTIVE:
			/* Save Changes to the options here. */
			ReadControls(hDlg);
			ResetDataMap();
			pGameOpts->use_default = g_bUseDefaults;
			PropToOptions(hDlg, pGameOpts);
			SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
			return 1;  

		case PSN_RESET:
			/* Reset to the original values. Disregard changes */
			memcpy(pGameOpts, &origGameOpts, sizeof(options_type));
			SetWindowLong(hDlg, DWL_MSGRESULT, FALSE);
			break;

		case PSN_HELP:
			/* User wants help for this property page */
			break;
		}
		break;

	}
	EnableWindow(GetDlgItem(hDlg, IDC_PROP_RESET), g_bReset);

	return 0;
}

static INT_PTR CALLBACK GameDisplayOptionsProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
	switch (Msg)
	{
	case WM_INITDIALOG:
		{
		}
	}

	return GameOptionsProc(hDlg, Msg, wParam, lParam);
}

/* Read controls that are not handled in the DataMap */
static void PropToOptions(HWND hWnd, options_type *o)
{
	char buf[100];
	HWND hCtrl;
	HWND hCtrl2;
	int  nIndex;

	o->use_default = g_bUseDefaults;

	/* resolution size */
	hCtrl = GetDlgItem(hWnd, IDC_SIZES);
	if (hCtrl)
	{
		/* Screen size control */
		nIndex = ComboBox_GetCurSel(hCtrl);
		
		if (nIndex == 0)
			strcpy(o->resolution, "0x0"); /* auto */
		else
		{
			int w, h;
        
			ComboBox_GetText(hCtrl, buf, 100);
			if (sscanf(buf, "%d x %d", &w, &h) == 2)
			{
				sprintf(o->resolution, "%dx%d", w, h);
			}
			else
			{
				strcpy(o->resolution, "0x0"); /* auto */
			}
		}   

		/* resolution depth */
		hCtrl = GetDlgItem(hWnd, IDC_RESDEPTH);
		if (hCtrl)
		{
			int nResDepth = 0;

			nIndex = ComboBox_GetCurSel(hCtrl);
			if (nIndex != CB_ERR)
				nResDepth = ComboBox_GetItemData(hCtrl, nIndex);

			switch (nResDepth)
			{
			default:
			case 0:  strcat(o->resolution, "x0"); break;
			case 16: strcat(o->resolution, "x16"); break;
			case 24: strcat(o->resolution, "x24"); break;
			case 32: strcat(o->resolution, "x32"); break;
			}
		}
	}

	/* refresh */
	hCtrl = GetDlgItem(hWnd, IDC_REFRESH);
	if (hCtrl)
	{
		nIndex = ComboBox_GetCurSel(hCtrl);
		
		pGameOpts->gfx_refresh = ComboBox_GetItemData(hCtrl, nIndex);
	}

	/* aspect ratio */
	hCtrl  = GetDlgItem(hWnd, IDC_ASPECTRATION);
	hCtrl2 = GetDlgItem(hWnd, IDC_ASPECTRATIOD);
	if (hCtrl && hCtrl2)
	{
		int n = 0;
		int d = 0;

		Edit_GetText(hCtrl, buf, sizeof(buf));
		sscanf(buf, "%d", &n);

		Edit_GetText(hCtrl2, buf, sizeof(buf));
		sscanf(buf, "%d", &d);

		if (n == 0 || d == 0)
		{
			n = 4;
			d = 3;
		}

		sprintf(o->aspect, "%d:%d", n, d);
	}

	/* keystone ratio */
	hCtrl  = GetDlgItem(hWnd, IDC_KEYSTONERATIOU);
	hCtrl2 = GetDlgItem(hWnd, IDC_KEYSTONERATIOD);
	if (hCtrl && hCtrl2)
	{
		int u = 0;
		int d = 0;

		Edit_GetText(hCtrl, buf, sizeof(buf));
		sscanf(buf, "%d", &u);

		Edit_GetText(hCtrl2, buf, sizeof(buf));
		sscanf(buf, "%d", &d);

		if (u == 0 || d == 0)
		{
			u = 1;
			d = 1;
		}

		sprintf(o->keystone, "%d:%d", u, d);
	}
}

/* Populate controls that are not handled in the DataMap */
static void OptionsToProp(HWND hWnd, options_type* o)
{
	HWND hCtrl;
	HWND hCtrl2;
	char buf[100];
	int  h = 0;
	int  w = 0;
	int  n = 0;
	int  d = 0;
	int  u = 0;

	g_bInternalSet = TRUE;

	/* video */

	/* get desired resolution */
	if (!stricmp(o->resolution, "auto"))
	{
		w = h = 0;
	}
	else
	if (sscanf(o->resolution, "%dx%dx%d", &w, &h, &d) < 2)
	{
		w = h = d = 0;
	}

	/* Setup sizes list based on depth. */
	UpdateDisplayModeUI(hWnd, d, o->gfx_refresh);

	/* Screen size drop down list */
	hCtrl = GetDlgItem(hWnd, IDC_SIZES);
	if (hCtrl)
	{
		if (w == 0 && h == 0)
		{
			/* default to auto */
			ComboBox_SetCurSel(hCtrl, 0);
		}
		else
		{
			/* Select the mode in the list. */
			int nSelection = 0;
			int nCount = 0;

			/* Get the number of items in the control */
			nCount = ComboBox_GetCount(hCtrl);
        
			while (0 < nCount--)
			{
				int nWidth, nHeight;
            
				/* Get the screen size */
				ComboBox_GetLBText(hCtrl, nCount, buf);
            
				if (sscanf(buf, "%d x %d", &nWidth, &nHeight) == 2)
				{
					/* If we match, set nSelection to the right value */
					if (w == nWidth
					&&  h == nHeight)
					{
						nSelection = nCount;
						break;
					}
				}
			}
			ComboBox_SetCurSel(hCtrl, nSelection);
		}
	}

	/* Screen depth drop down list */
	hCtrl = GetDlgItem(hWnd, IDC_RESDEPTH);
	if (hCtrl)
	{
		if (d == 0)
		{
			/* default to auto */
			ComboBox_SetCurSel(hCtrl, 0);
		}
		else
		{
			/* Select the mode in the list. */
			int nSelection = 0;
			int nCount = 0;

			/* Get the number of items in the control */
			nCount = ComboBox_GetCount(hCtrl);
        
			while (0 < nCount--)
			{
				int nDepth;
            
				/* Get the screen depth */
				nDepth = ComboBox_GetItemData(hCtrl, nCount);
            
				/* If we match, set nSelection to the right value */
				if (d == nDepth)
				{
					nSelection = nCount;
					break;
				}
			}
			ComboBox_SetCurSel(hCtrl, nSelection);
		}
	}

	/* Screen refresh list */
	hCtrl = GetDlgItem(hWnd, IDC_REFRESH);
	if (hCtrl)
	{
		if (o->gfx_refresh == 0)
		{
			/* default to auto */
			ComboBox_SetCurSel(hCtrl, 0);
		}
		else
		{
			/* Select the mode in the list. */
			int nSelection = 0;
			int nCount = 0;

			/* Get the number of items in the control */
			nCount = ComboBox_GetCount(hCtrl);
        
			while (0 < nCount--)
			{
				int nRefresh;
            
				/* Get the screen depth */
				nRefresh = ComboBox_GetItemData(hCtrl, nCount);
            
				/* If we match, set nSelection to the right value */
				if (o->gfx_refresh == nRefresh)
				{
					nSelection = nCount;
					break;
				}
			}
			ComboBox_SetCurSel(hCtrl, nSelection);
		}
	}

	hCtrl = GetDlgItem(hWnd, IDC_BRIGHTNESSDISP);
	if (hCtrl)
	{
		sprintf(buf, "%03.02f", o->gfx_brightness);
		Static_SetText(hCtrl, buf);
	}

	/* aspect ratio */
	hCtrl  = GetDlgItem(hWnd, IDC_ASPECTRATION);
	hCtrl2 = GetDlgItem(hWnd, IDC_ASPECTRATIOD);
	if (hCtrl && hCtrl2)
	{
		n = 0;
		d = 0;

		if (sscanf(o->aspect, "%d:%d", &n, &d) == 2 && n != 0 && d != 0)
		{
			sprintf(buf, "%d", n);
			Edit_SetText(hCtrl, buf);
			sprintf(buf, "%d", d);
			Edit_SetText(hCtrl2, buf);
		}
		else
		{
			Edit_SetText(hCtrl,  "4");
			Edit_SetText(hCtrl2, "3");
		}
	}

	/* keystone ratio */
	hCtrl  = GetDlgItem(hWnd, IDC_KEYSTONERATIOU);
	hCtrl2 = GetDlgItem(hWnd, IDC_KEYSTONERATIOD);
	if (hCtrl && hCtrl2)
	{
		u = 0;
		d = 0;

		if (sscanf(o->keystone, "%d:%d", &u, &d) == 2 && u != 0 && d != 0)
		{
			sprintf(buf, "%d", u);
			Edit_SetText(hCtrl, buf);
			sprintf(buf, "%d", d);
			Edit_SetText(hCtrl2, buf);
		}
		else
		{
			Edit_SetText(hCtrl,  "1");
			Edit_SetText(hCtrl2, "1");
		}
	}

	/* core video */
	hCtrl = GetDlgItem(hWnd, IDC_GAMMADISP);
	if (hCtrl)
	{
		sprintf(buf, "%03.02f", o->f_gamma_correct);
		Static_SetText(hCtrl, buf);
	}

	/* brightness correct */
	hCtrl = GetDlgItem(hWnd, IDC_BRIGHTCORRECTDISP);
	if (hCtrl)
	{
		sprintf(buf, "%03.02f", o->f_bright_correct);
		Static_SetText(hCtrl, buf);
	}

	/* Input */
	hCtrl = GetDlgItem(hWnd, IDC_A2DDISP);
	if (hCtrl)
	{
		sprintf(buf, "%03.02f", o->f_a2d);
		Static_SetText(hCtrl, buf);
	}

	/* sound */
	hCtrl = GetDlgItem(hWnd, IDC_VOLUMEDISP);
	if (hCtrl)
	{
		sprintf(buf, "%ddB", o->attenuation);
		Static_SetText(hCtrl, buf);
	}

	/* DirectSound buffer */
	hCtrl = GetDlgItem(hWnd, IDC_DSBUFFER_DISP);
	if (hCtrl)
	{
		sprintf(buf, "%dms", o->dsound_buffer);
		Static_SetText(hCtrl, buf);
	}

	/* RandomPlay time */
	hCtrl = GetDlgItem(hWnd, IDC_RANDOMTIME_DISP);
	if (hCtrl)
	{
		/* Set the static display to the new value */
		sprintf(buf, "%ds", o->random_time);
		Static_SetText(hCtrl, buf);
	}

	/* transparency */
	hCtrl = GetDlgItem(hWnd, IDC_TRANSDISP);
	if (hCtrl)
	{
		sprintf(buf, "%3d%%", o->transparency);
		Static_SetText(hCtrl, buf);
	}

	/* rotation */
	hCtrl = GetDlgItem(hWnd, IDC_ROTATION_DISP);
	if (hCtrl)
	{
		sprintf(buf, "%3d%s", o->rotation, win32_getstring(WIN32_property_degrees));
		Static_SetText(hCtrl, buf);
	}

	/* zoom x */
	hCtrl = GetDlgItem(hWnd, IDC_ZOOMX_DISP);
	if (hCtrl)
	{
		sprintf(buf, "%02.01f", o->zoomx);
		Static_SetText(hCtrl, buf);
	}

	/* zoom y */
	hCtrl = GetDlgItem(hWnd, IDC_ZOOMY_DISP);
	if (hCtrl)
	{
		sprintf(buf, "%02.01f", o->zoomy);
		Static_SetText(hCtrl, buf);
	}

	g_bInternalSet = FALSE;

	g_nInputIndex = 0;
	hCtrl = GetDlgItem(hWnd, IDC_DEFAULT_INPUT);	
	if (hCtrl)
	{
		int nCount;

		/* Get the number of items in the control */
		nCount = ComboBox_GetCount(hCtrl);

		while (0 < nCount--)
		{
			ComboBox_GetLBText(hCtrl, nCount, buf);

			if (stricmp (buf,o->ctrlr) == 0)
				g_nInputIndex = nCount;
		}

		ComboBox_SetCurSel(hCtrl, g_nInputIndex);
	}
}

/* Adjust controls - tune them to the currently selected game */
static void SetPropEnabledControls(HWND hWnd)
{
	HWND hCtrl;
	int  nIndex;
	int  sound;
	int  i;

	nIndex = g_nGame;

	EnableWindow(GetDlgItem(hWnd, IDC_WAITVSYNC),         !Button_GetCheck(GetDlgItem(hWnd, IDC_TRIPLE_BUFFER)));
	EnableWindow(GetDlgItem(hWnd, IDC_TRIPLE_BUFFER),     !Button_GetCheck(GetDlgItem(hWnd, IDC_WAITVSYNC)));
	EnableWindow(GetDlgItem(hWnd, IDC_HWSTRETCH),         DirectDraw_HasHWStretch());
	EnableWindow(GetDlgItem(hWnd, IDC_REFRESH),           DirectDraw_HasRefresh());
	EnableWindow(GetDlgItem(hWnd, IDC_REFRESHTEXT),       DirectDraw_HasRefresh());
	EnableWindow(GetDlgItem(hWnd, IDC_ASPECTRATIOTEXT),   DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)));
	EnableWindow(GetDlgItem(hWnd, IDC_ASPECTRATION),      DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)));
	EnableWindow(GetDlgItem(hWnd, IDC_ASPECTRATIOD),      DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)));
	EnableWindow(GetDlgItem(hWnd, IDC_DIRECT3D),          DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)));
	EnableWindow(GetDlgItem(hWnd, IDC_VIEWTEXT),          DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_MOTIONBLUR),        DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_BILINEAR),          DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_KEYSTONE),          DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_KEYSTONERATIOTEXT), DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_KEYSTONERATIOU),    DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_KEYSTONERATIOD),    DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ZOOMXTEXT),         DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ZOOMX),             DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ZOOMX_DISP),        DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ZOOMYTEXT),         DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ZOOMY),             DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ZOOMY_DISP),        DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ROTATIONTEXT),      DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ROTATION),          DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));
	EnableWindow(GetDlgItem(hWnd, IDC_ROTATION_DISP),     DirectDraw_HasHWStretch() && Button_GetCheck(GetDlgItem(hWnd, IDC_HWSTRETCH)) && Button_GetCheck(GetDlgItem(hWnd, IDC_DIRECT3D)));

	hCtrl = GetDlgItem(hWnd, IDC_JOYSTICK);
	if (hCtrl)
		Button_Enable(hCtrl, DIJoystick.Available());

	/* Trackball / Mouse options */
	if (nIndex == -1 || GameUsesTrackball(nIndex))
	{
		Button_Enable(GetDlgItem(hWnd, IDC_USE_MOUSE), TRUE);
	}
	else
	{
		Button_Enable(GetDlgItem(hWnd, IDC_USE_MOUSE), FALSE);
	}

	/* Sound options */
	hCtrl = GetDlgItem(hWnd, IDC_USE_SOUND);
	if (hCtrl)
	{
		sound = Button_GetCheck(hCtrl);
		ComboBox_Enable(GetDlgItem(hWnd, IDC_SAMPLERATE), (sound != 0));

		EnableWindow(GetDlgItem(hWnd, IDC_VOLUME),          (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_RATETEXT),        (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_VOLUMEDISP),      (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_VOLUMETEXT),      (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_DSBUFFER),        (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_DSBUFFER_DISP),   (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_DSBUFFER_TEXT),   (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_RANDOMTIME),      (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_RANDOMTIME_DISP), (sound != 0));
		EnableWindow(GetDlgItem(hWnd, IDC_RANDOMTIME_TEXT), (sound != 0));

		if (sound)
			SetStereoEnabled(hWnd, nIndex);
		else
			EnableWindow(GetDlgItem(hWnd, IDC_STEREO), FALSE);
	}

	if (Button_GetCheck(GetDlgItem(hWnd, IDC_AUTOFRAMESKIP)))
		EnableWindow(GetDlgItem(hWnd, IDC_FRAMESKIP), FALSE);
	else
		EnableWindow(GetDlgItem(hWnd, IDC_FRAMESKIP), TRUE);

	if (Button_GetCheck(GetDlgItem(hWnd, IDC_WINDOWED)))
	{
		EnableWindow(GetDlgItem(hWnd, IDC_WINDOWTEXT), TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_WINDOWSIZE), TRUE);
	}
	else
	{
		EnableWindow(GetDlgItem(hWnd, IDC_WINDOWTEXT), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_WINDOWSIZE), FALSE);
	}

	if (Button_GetCheck(GetDlgItem(hWnd, IDC_JOYSTICK)) && DIJoystick.Available())
	{
		EnableWindow(GetDlgItem(hWnd, IDC_JOYIDTEXT),  TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_A2DTEXT),    TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_A2DDISP),    TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_A2D),        TRUE);

		for (i = 0; i < 4; i++)
		{
			if (i < DIJoystick_GetNumPhysicalJoysticks())
			{
				EnableWindow(GetDlgItem(hWnd, IDC_JOYID1 + i),     TRUE);
				EnableWindow(GetDlgItem(hWnd, IDC_JOYID1TEXT + i), TRUE);
			}
			else
			{
				EnableWindow(GetDlgItem(hWnd, IDC_JOYID1 + i),     FALSE);
				EnableWindow(GetDlgItem(hWnd, IDC_JOYID1TEXT + i), FALSE);
			}
		}
	}
	else
	{
		EnableWindow(GetDlgItem(hWnd, IDC_JOYIDTEXT),  FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID1),     FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID2),     FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID3),     FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID4),     FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID1TEXT), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID2TEXT), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID3TEXT), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_JOYID4TEXT), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_A2DTEXT),    FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_A2DDISP),    FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_A2D),        FALSE);
	}

	if (nIndex == -1 || GameUsesRomPatch(nIndex))
	{
		Button_Enable(GetDlgItem(hWnd, IDC_PATCH_ROMS), TRUE);
	}
	else
	{
		Button_SetCheck(GetDlgItem(hWnd, IDC_PATCH_ROMS), TRUE);
		Button_Enable(GetDlgItem(hWnd, IDC_PATCH_ROMS), FALSE);
	}

	if (nIndex != -1 && drivers[nIndex]->system != SYSTEM_NEOGEO)
	{
		ComboBox_SetCurSel(GetDlgItem(hWnd, IDC_BIOSTYPE), 0);
		ComboBox_Enable(GetDlgItem(hWnd, IDC_BIOSTYPE), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_NEOGEOTEXT), FALSE);
		EnableWindow(GetDlgItem(hWnd, IDC_BIOSTYPETEXT), FALSE);
	}
	else
	{
		ComboBox_Enable(GetDlgItem(hWnd, IDC_BIOSTYPE), TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_NEOGEOTEXT), TRUE);
		EnableWindow(GetDlgItem(hWnd, IDC_BIOSTYPETEXT), TRUE);
	}
}

/**************************************************************
 * Control Helper functions for data exchange
 **************************************************************/

static void AssignSampleRate(HWND hWnd)
{
	switch (g_nSampleRateIndex)
	{
		case 0:  pGameOpts->samplerate = 11025; break;
		case 1:  pGameOpts->samplerate = 22050; break;
		case 2:  pGameOpts->samplerate = 24000; break;
		case 3:  pGameOpts->samplerate = 44100; break;
		case 4:  pGameOpts->samplerate = 48000; break;
		default: pGameOpts->samplerate = 44100; break;
	}
}

static void AssignVolume(HWND hWnd)
{
	pGameOpts->attenuation = g_nVolumeIndex - 32;
}

static void AssignBrightCorrect(HWND hWnd)
{
	/* "1.0", 0.5, 2.0 */
	pGameOpts->f_bright_correct = g_nBrightCorrectIndex / 20.0 + 0.5;
	
}

static void AssignGamma(HWND hWnd)
{
	pGameOpts->f_gamma_correct = g_nGammaIndex / 20.0 + 0.5;
}

static void AssignBrightness(HWND hWnd)
{
	pGameOpts->gfx_brightness = g_nBrightnessIndex / 20.0 + 0.1;
}

static void AssignA2D(HWND hWnd)
{
	pGameOpts->f_a2d = g_nA2DIndex / 20.0;
}

static void AssignRotate(HWND hWnd)
{
	pGameOpts->ror = 0;
	pGameOpts->rol = 0;

	switch (g_nRotateIndex)
	{
		case 1:  pGameOpts->ror = 1; break;
		case 2:  pGameOpts->rol = 1; break;
		default: break;
	}
}

static void AssignInput(HWND hWnd)
{
	ComboBox_GetLBText (hWnd, g_nInputIndex, pGameOpts->ctrlr);
}

static void AssignEffect(HWND hWnd)
{
	const char* pData = (const char*)ComboBox_GetItemData(hWnd, g_nEffectIndex);
	if (pData != NULL)
		strcpy(pGameOpts->effect, pData);
}

static void AssignZoomx(HWND hWnd)
{
	pGameOpts->zoomx = g_nZoomxIndex / 10.0 - 10.0;
}

static void AssignZoomy(HWND hWnd)
{
	pGameOpts->zoomy = g_nZoomyIndex / 10.0 - 10.0;
}

/************************************************************
 * DataMap initializers
 ************************************************************/

/* Initialize local helper variables */
static void ResetDataMap(void)
{
	int i;
	g_nGammaIndex         = (int)((pGameOpts->f_gamma_correct -  0.5) * 20.0);
	g_nBrightCorrectIndex = (int)((pGameOpts->f_bright_correct - 0.5) * 20.0);
	g_nBrightnessIndex    = (int)((pGameOpts->gfx_brightness  -  0.1) * 20.0);
	g_nZoomxIndex         = (int)((pGameOpts->zoomx           + 10.0) * 10.0);
	g_nZoomyIndex         = (int)((pGameOpts->zoomy           + 10.0) * 10.0);
	g_nA2DIndex           = (int)(pGameOpts->f_a2d                    * 20.0);

	// if no controller type was specified or it was standard
	if ((pGameOpts->ctrlr == NULL) || *pGameOpts->ctrlr == 0 || (stricmp(pGameOpts->ctrlr,"Standard") == 0))
	{
		strcpy (pGameOpts->ctrlr, "Standard");
	}

	if (pGameOpts->ror == 0 && pGameOpts->rol == 0)
		g_nRotateIndex = 0;
	else
	if (pGameOpts->ror == 1 && pGameOpts->rol == 0)
		g_nRotateIndex = 1;
	else
	if (pGameOpts->ror == 0 && pGameOpts->rol == 1)
		g_nRotateIndex = 2;
	else
		g_nRotateIndex = 0;

	g_nVolumeIndex = pGameOpts->attenuation + 32;
	switch (pGameOpts->samplerate)
	{
		case 11025:  g_nSampleRateIndex = 0; break;
		case 22050:  g_nSampleRateIndex = 1; break;
		case 24000:  g_nSampleRateIndex = 2; break;
		default:
		case 44100:  g_nSampleRateIndex = 3; break;
		case 48000:  g_nSampleRateIndex = 4; break;
	}

	g_nEffectIndex = 0;
	for (i = 0; i < NUMEFFECTS; i++)
	{
		if (!stricmp(pGameOpts->effect, g_ComboBoxEffect[i].m_pData))
			g_nEffectIndex = i;
	}
}

/* Build the control mapping by adding all needed information to the DataMap */
static void BuildDataMap(void)
{
	InitDataMap();

	ResetDataMap();

	/* video */
	DataMapAdd(IDC_AUTOFRAMESKIP, DM_BOOL, CT_BUTTON,   &pGameOpts->autoframeskip, 0, 0, 0);
	DataMapAdd(IDC_FRAMESKIP,     DM_INT,  CT_COMBOBOX, &pGameOpts->frameskip,     0, 0, 0);
	DataMapAdd(IDC_WAITVSYNC,     DM_BOOL, CT_BUTTON,   &pGameOpts->wait_vsync,    0, 0, 0);
	DataMapAdd(IDC_TRIPLE_BUFFER, DM_BOOL, CT_BUTTON,   &pGameOpts->use_triplebuf, 0, 0, 0);
	DataMapAdd(IDC_WINDOWED,      DM_BOOL, CT_BUTTON,   &pGameOpts->window_mode,   0, 0, 0);
	DataMapAdd(IDC_HWSTRETCH,     DM_BOOL, CT_BUTTON,   &pGameOpts->ddraw_stretch, 0, 0, 0);
	/* pGameOpts->resolution */
	/* pGameOpts->gfx_refresh */
	DataMapAdd(IDC_SCANLINES,     DM_BOOL, CT_BUTTON,   &pGameOpts->scanlines,     0, 0, 0);
	DataMapAdd(IDC_SWITCHRES,     DM_BOOL, CT_BUTTON,   &pGameOpts->switchres,     0, 0, 0);
	DataMapAdd(IDC_SWITCHBPP,     DM_BOOL, CT_BUTTON,   &pGameOpts->switchbpp,     0, 0, 0);
	DataMapAdd(IDC_WINDOWSIZE,    DM_INT,  CT_COMBOBOX, &pGameOpts->windowsize,    0, 0, 0);
	DataMapAdd(IDC_KEEPASPECT,    DM_BOOL, CT_BUTTON,   &pGameOpts->keepaspect,    0, 0, 0);
	DataMapAdd(IDC_MATCHREFRESH,  DM_BOOL, CT_BUTTON,   &pGameOpts->matchrefresh,  0, 0, 0);
	DataMapAdd(IDC_SYNCREFRESH,   DM_BOOL, CT_BUTTON,   &pGameOpts->syncrefresh,   0, 0, 0);
	DataMapAdd(IDC_THROTTLE,      DM_BOOL, CT_BUTTON,   &pGameOpts->throttle,      0, 0, 0);
	DataMapAdd(IDC_BRIGHTNESS,    DM_INT,  CT_SLIDER,   &g_nBrightnessIndex,       0, 0, AssignBrightness);
	DataMapAdd(IDC_SYSTEMMEMORY,  DM_BOOL, CT_BUTTON,   &pGameOpts->systemmemory,  0, 0, 0);
	/* pGameOpts->frames_to_display */
	DataMapAdd(IDC_EFFECT,        DM_INT,  CT_COMBOBOX, &g_nEffectIndex,           0, 0, AssignEffect);
	/* pGameOpts->aspect */

	/* input */
	DataMapAdd(IDC_DEFAULT_INPUT, DM_INT,  CT_COMBOBOX, &g_nInputIndex,            0, 0, AssignInput);
	DataMapAdd(IDC_USE_MOUSE,     DM_BOOL, CT_BUTTON,   &pGameOpts->use_mouse,     0, 0, 0);   
	DataMapAdd(IDC_JOYSTICK,      DM_BOOL, CT_BUTTON,   &pGameOpts->use_joystick,  0, 0, 0);   
	DataMapAdd(IDC_A2D,           DM_INT,  CT_SLIDER,   &g_nA2DIndex,              0, 0, AssignA2D);
	DataMapAdd(IDC_STEADYKEY,     DM_BOOL, CT_BUTTON,   &pGameOpts->steadykey,     0, 0, 0);   
	DataMapAdd(IDC_JOYID1,        DM_INT,  CT_COMBOBOX, &pGameOpts->joyid[0],      0, 0, 0);
	DataMapAdd(IDC_JOYID2,        DM_INT,  CT_COMBOBOX, &pGameOpts->joyid[1],      0, 0, 0);
	DataMapAdd(IDC_JOYID3,        DM_INT,  CT_COMBOBOX, &pGameOpts->joyid[2],      0, 0, 0);
	DataMapAdd(IDC_JOYID4,        DM_INT,  CT_COMBOBOX, &pGameOpts->joyid[3],      0, 0, 0);

	/* core video */
	DataMapAdd(IDC_BRIGHTCORRECT, DM_INT,  CT_SLIDER,   &g_nBrightCorrectIndex,    0, 0, AssignBrightCorrect);
	DataMapAdd(IDC_NOROTATE,      DM_BOOL, CT_BUTTON,   &pGameOpts->norotate,      0, 0, 0);
	DataMapAdd(IDC_ROTATE,        DM_INT,  CT_COMBOBOX, &g_nRotateIndex,           0, 0, AssignRotate);
	DataMapAdd(IDC_FLIPX,         DM_BOOL, CT_BUTTON,   &pGameOpts->flipx,         0, 0, 0);
	DataMapAdd(IDC_FLIPY,         DM_BOOL, CT_BUTTON,   &pGameOpts->flipy,         0, 0, 0);
	/* debugres */
	DataMapAdd(IDC_GAMMA,         DM_INT,  CT_SLIDER,   &g_nGammaIndex,            0, 0, AssignGamma);

	/* advanced video */
	DataMapAdd(IDC_DIRECT3D,      DM_BOOL, CT_BUTTON,   &pGameOpts->direct3d,      0, 0, 0);
	DataMapAdd(IDC_MOTIONBLUR,    DM_BOOL, CT_BUTTON,   &pGameOpts->motionblur,    0, 0, 0);
	DataMapAdd(IDC_BILINEAR,      DM_BOOL, CT_BUTTON,   &pGameOpts->bilinear,      0, 0, 0);
	DataMapAdd(IDC_ROTATION,      DM_INT,  CT_SLIDER,   &pGameOpts->rotation,      0, 0, 0);
	DataMapAdd(IDC_ZOOMX,         DM_INT,  CT_SLIDER,   &g_nZoomxIndex,            0, 0, AssignZoomx);
	DataMapAdd(IDC_ZOOMY,         DM_INT,  CT_SLIDER,   &g_nZoomyIndex,            0, 0, AssignZoomy);

	/* sound */
	DataMapAdd(IDC_SAMPLERATE,    DM_INT,  CT_COMBOBOX, &g_nSampleRateIndex,       0, 0, AssignSampleRate);
	DataMapAdd(IDC_USE_SOUND,     DM_BOOL, CT_BUTTON,   &pGameOpts->enable_sound,  0, 0, 0);
	DataMapAdd(IDC_STEREO,        DM_BOOL, CT_BUTTON,   &pGameOpts->stereo,        0, 0, 0);
	DataMapAdd(IDC_VOLUME,        DM_INT,  CT_SLIDER,   &g_nVolumeIndex,           0, 0, AssignVolume);
	DataMapAdd(IDC_DSBUFFER,      DM_INT,  CT_SLIDER,   &pGameOpts->dsound_buffer, 0, 0, 0);
	DataMapAdd(IDC_RANDOMTIME,    DM_INT,  CT_SLIDER,   &pGameOpts->random_time,   0, 0, 0);

	/* misc */
	DataMapAdd(IDC_CHEAT,         DM_BOOL, CT_BUTTON,   &pGameOpts->cheat,         0, 0, 0);
/*	DataMapAdd(IDC_DEBUG,         DM_BOOL, CT_BUTTON,   &pGameOpts->mame_debug,    0, 0, 0);*/
	DataMapAdd(IDC_LOG,           DM_BOOL, CT_BUTTON,   &pGameOpts->errorlog,      0, 0, 0);
	DataMapAdd(IDC_PATCH_ROMS,    DM_BOOL, CT_BUTTON,   &pGameOpts->patch_roms,    0, 0, 0);
	DataMapAdd(IDC_BIOSTYPE,      DM_INT,  CT_COMBOBOX, &pGameOpts->bios_type,     0, 0, 0);
	DataMapAdd(IDC_TRANSPARENT,   DM_INT,  CT_SLIDER,   &pGameOpts->transparency,  0, 0, 0);
	DataMapAdd(IDC_SLEEP,         DM_BOOL, CT_BUTTON,   &pGameOpts->sleep,         0, 0, 0);
	DataMapAdd(IDC_LEDS,          DM_BOOL, CT_BUTTON,   &pGameOpts->leds,          0, 0, 0);
}

static void SetStereoEnabled(HWND hWnd, int nIndex)
{
	BOOL enabled = FALSE;
	HWND hCtrl;
    struct InternalMachineDriver drv;

	if (-1 != nIndex)
		expand_machine_driver(drivers[nIndex]->drv,&drv);

	hCtrl = GetDlgItem(hWnd, IDC_STEREO);
	if (hCtrl)
	{
		if (nIndex == -1 || drv.sound_attributes & SOUND_SUPPORTS_STEREO)
			enabled = TRUE;

		EnableWindow(hCtrl, enabled);
	}
}

/* Moved here cause it's called in a few places */
static void InitializeOptions(HWND hDlg)
{
	InitializeResDepthUI(hDlg);
	InitializeRefreshUI(hDlg);
	InitializeDisplayModeUI(hDlg);
	InitializeSoundUI(hDlg);
	InitializeSkippingUI(hDlg);
	InitializeRotateUI(hDlg);
	InitializeDefaultInputUI(hDlg);
	InitializeEffectUI(hDlg);
	InitializeBiosUI(hDlg);
	InitializeWindowSizeUI(hDlg);
	InitializeJoyidUI(hDlg);
}

/* Moved here because it is called in several places */
static void InitializeMisc(HWND hDlg)
{
	Button_Enable(GetDlgItem(hDlg, IDC_JOYSTICK), DIJoystick.Available());

	SendMessage(GetDlgItem(hDlg, IDC_GAMMA), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 30)); /* [0.50, 2.00] in .05 increments */

	SendMessage(GetDlgItem(hDlg, IDC_BRIGHTCORRECT), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 30)); /* [0.50, 2.00] in .05 increments */

	SendMessage(GetDlgItem(hDlg, IDC_BRIGHTNESS), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 38)); /* [0.10, 2.00] in .05 increments */

	SendMessage(GetDlgItem(hDlg, IDC_A2D), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 20)); /* [0.00, 1.00] in .05 increments */

	SendMessage(GetDlgItem(hDlg, IDC_VOLUME), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 32)); /* [-32, 0] */

	SendMessage(GetDlgItem(hDlg, IDC_TRANSPARENT), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 100));

	SendMessage(GetDlgItem(hDlg, IDC_DSBUFFER), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(50, 200));

	SendMessage(GetDlgItem(hDlg, IDC_RANDOMTIME), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(30, 300));

	SendMessage(GetDlgItem(hDlg, IDC_ROTATION), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 360));

	SendMessage(GetDlgItem(hDlg, IDC_ZOOMX), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 200)); /* [-10.0, 10.0] in .1 increments */

	SendMessage(GetDlgItem(hDlg, IDC_ZOOMY), TBM_SETRANGE,
				(WPARAM)FALSE,
				(LPARAM)MAKELONG(0, 200)); /* [-10.0, 10.0] in .1 increments */
}

static void OptOnHScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
{
	if (hwndCtl == GetDlgItem(hwnd, IDC_GAMMA))
	{
		GammaSelectionChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_BRIGHTCORRECT))
	{
		BrightCorrectSelectionChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_BRIGHTNESS))
	{
		BrightnessSelectionChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_VOLUME))
	{
		VolumeSelectionChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_TRANSPARENT))
	{
		TransparentChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_DSBUFFER))
	{
		DSoundBufferSelectionChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_RANDOMTIME))
	{
		RandomPlayTimeSelectionChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_ROTATION))
	{
		RotationChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_ZOOMX))
	{
		ZoomxChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_ZOOMY))
	{
		ZoomyChange(hwnd);
	}
	else
	if (hwndCtl == GetDlgItem(hwnd, IDC_A2D))
	{
		A2DSelectionChange(hwnd);
	}
}

/* Handle changes to the Gamma slider */
static void GammaSelectionChange(HWND hwnd)
{
	char   buf[100];
	UINT   nValue;
	double dGamma;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_GAMMA), TBM_GETPOS, 0, 0);

	dGamma = nValue / 20.0 + 0.5;

	/* Set the static display to the new value */
	sprintf(buf, "%03.02f", dGamma);
	Static_SetText(GetDlgItem(hwnd, IDC_GAMMADISP), buf);
}

/* Handle changes to the Brightness Correction slider */
static void BrightCorrectSelectionChange(HWND hwnd)
{
	char   buf[100];
	UINT   nValue;
	double dValue;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_BRIGHTCORRECT), TBM_GETPOS, 0, 0);

	dValue = nValue / 20.0 + 0.5;

	/* Set the static display to the new value */
	sprintf(buf, "%03.02f", dValue);
	Static_SetText(GetDlgItem(hwnd, IDC_BRIGHTCORRECTDISP), buf);
}

/* Handle changes to the Brightness slider */
static void BrightnessSelectionChange(HWND hwnd)
{
	char   buf[100];
	int    nValue;
	double dBrightness;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_BRIGHTNESS), TBM_GETPOS, 0, 0);

	dBrightness = nValue / 20.0 + 0.1;

	/* Set the static display to the new value */
	sprintf(buf, "%03.02f", dBrightness);
	Static_SetText(GetDlgItem(hwnd, IDC_BRIGHTNESSDISP), buf);
}

/* Handle changes to the A2D slider */
static void A2DSelectionChange(HWND hwnd)
{
	char   buf[100];
	UINT   nValue;
	double dA2D;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_A2D), TBM_GETPOS, 0, 0);

	dA2D = nValue / 20.0;

	/* Set the static display to the new value */
	sprintf(buf, "%03.02f", dA2D);
	Static_SetText(GetDlgItem(hwnd, IDC_A2DDISP), buf);
}

/* Handle changes to the Color Depth drop down */
static void ResDepthSelectionChange(HWND hWnd, HWND hWndCtrl)
{
	int nCurSelection;

	nCurSelection = ComboBox_GetCurSel(hWndCtrl);
	if (nCurSelection != CB_ERR)
	{
		HWND hRefreshCtrl;
		int nResDepth = 0;
		int nRefresh  = 0;
    
		nResDepth = ComboBox_GetItemData(hWndCtrl, nCurSelection);

		hRefreshCtrl = GetDlgItem(hWnd, IDC_REFRESH);
		if (hRefreshCtrl)
		{
			nCurSelection = ComboBox_GetCurSel(hRefreshCtrl);
			if (nCurSelection != CB_ERR)
				nRefresh = ComboBox_GetItemData(hRefreshCtrl, nCurSelection);
		}

		UpdateDisplayModeUI(hWnd, nResDepth, nRefresh);
	}
}

/* Handle changes to the Refresh drop down */
static void RefreshSelectionChange(HWND hWnd, HWND hWndCtrl)
{
	int nCurSelection;

	nCurSelection = ComboBox_GetCurSel(hWndCtrl);
	if (nCurSelection != CB_ERR)
	{
		HWND hResDepthCtrl;
		int nResDepth = 0;
		int nRefresh  = 0;
    
		nRefresh = ComboBox_GetItemData(hWndCtrl, nCurSelection);

		hResDepthCtrl = GetDlgItem(hWnd, IDC_RESDEPTH);
		if (hResDepthCtrl)
		{
			nCurSelection = ComboBox_GetCurSel(hResDepthCtrl);
			if (nCurSelection != CB_ERR)
				nResDepth = ComboBox_GetItemData(hResDepthCtrl, nCurSelection);
		}

		UpdateDisplayModeUI(hWnd, nResDepth, nRefresh);
	}
}

/* Handle changes to the Volume slider */
static void VolumeSelectionChange(HWND hwnd)
{
	char buf[100];
	int  nValue;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_VOLUME), TBM_GETPOS, 0, 0);

	/* Set the static display to the new value */
	sprintf(buf, "%ddB", nValue - 32);
	Static_SetText(GetDlgItem(hwnd, IDC_VOLUMEDISP), buf);
}

/* Handle changes to the Transparent slider */
static void TransparentChange(HWND hwnd)
{
	char buf[100];
	int  nValue;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_TRANSPARENT), TBM_GETPOS, 0, 0);

	/* Set the static display to the new value */
	sprintf(buf, "%3d%%", nValue);
	Static_SetText(GetDlgItem(hwnd, IDC_TRANSDISP), buf);
}

/* Handle changes to the DirectSoundBuffer slider */
static void DSoundBufferSelectionChange(HWND hwnd)
{
	char buf[100];
	int  nValue;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_DSBUFFER), TBM_GETPOS, 0, 0);

	/* Set the static display to the new value */
	sprintf(buf, "%3dms", nValue);
	Static_SetText(GetDlgItem(hwnd, IDC_DSBUFFER_DISP), buf);
}

/* Handle changes to the Random Time slider */
static void RandomPlayTimeSelectionChange(HWND hwnd)
{
	char buf[100];
	int  nValue;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_RANDOMTIME), TBM_GETPOS, 0, 0);

	/* Set the static display to the new value */
	sprintf(buf, "%ds", nValue);
	Static_SetText(GetDlgItem(hwnd, IDC_RANDOMTIME_DISP), buf);
}

/* Handle changes to the Rotation slider */
static void RotationChange(HWND hwnd)
{
	char buf[100];
	int  nValue;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_ROTATION), TBM_GETPOS, 0, 0);

	/* Set the static display to the new value */
	sprintf(buf, "%3d%s", nValue, win32_getstring(WIN32_property_degrees));
	Static_SetText(GetDlgItem(hwnd, IDC_ROTATION_DISP), buf);
}

/* Handle changes to the Zoom x slider */
static void ZoomxChange(HWND hwnd)
{
	char   buf[100];
	UINT   nValue;
	double dZoomx;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_ZOOMX), TBM_GETPOS, 0, 0);

	dZoomx = nValue / 10.0 - 10.0;

	/* Set the static display to the new value */
	sprintf(buf, "%02.01f", dZoomx);
	Static_SetText(GetDlgItem(hwnd, IDC_ZOOMX_DISP), buf);
}

/* Handle changes to the Zoom y slider */
static void ZoomyChange(HWND hwnd)
{
	char   buf[100];
	UINT   nValue;
	double dZoomy;

	/* Get the current value of the control */
	nValue = SendMessage(GetDlgItem(hwnd, IDC_ZOOMY), TBM_GETPOS, 0, 0);

	dZoomy = nValue / 10.0 - 10.0;

	/* Set the static display to the new value */
	sprintf(buf, "%02.01f", dZoomy);
	Static_SetText(GetDlgItem(hwnd, IDC_ZOOMY_DISP), buf);
}

/* Adjust possible choices in the Screen Size drop down */
static void UpdateDisplayModeUI(HWND hwnd, DWORD dwDepth, DWORD dwRefresh)
{
	int                   i;
	char                  buf[100];
	struct tDisplayModes* pDisplayModes;
	int                   nPick;
	int                   nCount = 0;
	int                   nSelection = 0;
	DWORD                 w = 0, h = 0;
	HWND                  hCtrl = GetDlgItem(hwnd, IDC_SIZES);

	if (!hCtrl)
		return;

	/* Find out what is currently selected if anything. */
	nPick = ComboBox_GetCurSel(hCtrl);
	if (nPick != 0 && nPick != CB_ERR)
	{
		ComboBox_GetText(GetDlgItem(hwnd, IDC_SIZES), buf, 100);
		if (sscanf(buf, "%ld x %ld", &w, &h) != 2)
		{
			w = 0;
			h = 0;
		}
	}

	/* Remove all items in the list. */
	ComboBox_ResetContent(hCtrl);

	ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_auto));

	pDisplayModes = DirectDraw_GetDisplayModes();

	for (i = 0; i < pDisplayModes->m_nNumModes; i++)
	{
		if ((pDisplayModes->m_Modes[i].m_dwBPP     == dwDepth   || dwDepth   == 0)
		&&  (pDisplayModes->m_Modes[i].m_dwRefresh == dwRefresh || dwRefresh == 0))
		{
			sprintf(buf, "%li x %li", pDisplayModes->m_Modes[i].m_dwWidth,
									  pDisplayModes->m_Modes[i].m_dwHeight);

			if (ComboBox_FindString(hCtrl, 0, buf) == CB_ERR)
			{
				ComboBox_AddString(hCtrl, buf);
				nCount++;

				if (w == pDisplayModes->m_Modes[i].m_dwWidth
				&&  h == pDisplayModes->m_Modes[i].m_dwHeight)
					nSelection = nCount;
			}
		}
	}

	ComboBox_SetCurSel(hCtrl, nSelection);
}

/* Initialize the Display options to auto mode */
static void InitializeDisplayModeUI(HWND hwnd)
{
	UpdateDisplayModeUI(hwnd, 0, 0);
}

/* Initialize the sound options */
static void InitializeSoundUI(HWND hwnd)
{
	HWND    hCtrl;

	hCtrl = GetDlgItem(hwnd, IDC_SAMPLERATE);
	if (hCtrl)
	{
		ComboBox_AddString(hCtrl, "11025");
		ComboBox_AddString(hCtrl, "22050");
		ComboBox_AddString(hCtrl, "24000");
		ComboBox_AddString(hCtrl, "44100");
		ComboBox_AddString(hCtrl, "48000");
		ComboBox_SetCurSel(hCtrl, 3);
	}
}

/* Populate the Frame Skipping drop down */
static void InitializeSkippingUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_FRAMESKIP);

	if (hCtrl)
	{
		int i;
		char buf[80];

		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_everyframe));

		for (i = 1; i < 12; i++)
		{
			sprintf(buf, win32_getstring(WIN32_property_frameskip), i);
			ComboBox_AddString(hCtrl, buf);
		}
	}
}

/* Populate the Rotate drop down */
static void InitializeRotateUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_ROTATE);

	if (hCtrl)
	{
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_none));           /* 0 */
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_clockwise));      /* 1 */
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_anticlockwise));  /* 2 */
	}
}

/* Populate the resolution depth drop down */
static void InitializeResDepthUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_RESDEPTH);

	if (hCtrl)
	{
		struct tDisplayModes* pDisplayModes;
		int nCount = 0;
		int i;

		/* Remove all items in the list. */
		ComboBox_ResetContent(hCtrl);

		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_auto));
		ComboBox_SetItemData(hCtrl, nCount++, 0);

		pDisplayModes = DirectDraw_GetDisplayModes();

		for (i = 0; i < pDisplayModes->m_nNumModes; i++)
		{
			if (pDisplayModes->m_Modes[i].m_dwBPP == 16
			||  pDisplayModes->m_Modes[i].m_dwBPP == 24
			||  pDisplayModes->m_Modes[i].m_dwBPP == 32)
			{
				char buf[16];

				sprintf(buf, win32_getstring(WIN32_property_bits), pDisplayModes->m_Modes[i].m_dwBPP);

				if (ComboBox_FindString(hCtrl, 0, buf) == CB_ERR)
				{
					ComboBox_InsertString(hCtrl, nCount, buf);
					ComboBox_SetItemData(hCtrl, nCount++, pDisplayModes->m_Modes[i].m_dwBPP);
				}
			}
		}
	}
}

/* Populate the refresh drop down */
static void InitializeRefreshUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_REFRESH);

	if (hCtrl)
	{
		struct tDisplayModes* pDisplayModes;
		int nCount = 0;
		int i;

		/* Remove all items in the list. */
		ComboBox_ResetContent(hCtrl);

		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_auto));
		ComboBox_SetItemData(hCtrl, nCount++, 0);

		pDisplayModes = DirectDraw_GetDisplayModes();

		for (i = 0; i < pDisplayModes->m_nNumModes; i++)
		{
			if (pDisplayModes->m_Modes[i].m_dwRefresh != 0)
			{
				char buf[16];

				sprintf(buf, "%li Hz", pDisplayModes->m_Modes[i].m_dwRefresh);

				if (ComboBox_FindString(hCtrl, 0, buf) == CB_ERR)
				{
					ComboBox_InsertString(hCtrl, nCount, buf);
					ComboBox_SetItemData(hCtrl, nCount++, pDisplayModes->m_Modes[i].m_dwRefresh);
				}
			}
		}
	}
}

/* Populate the Default Input drop down */
static void InitializeDefaultInputUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_DEFAULT_INPUT);

	WIN32_FIND_DATA FindFileData;
	HANDLE hFind;
	char *ext;
	int isZipFile;
	char root[256];
	char path[256];

	if (hCtrl)
	{
		ComboBox_AddString(hCtrl, "Standard");

		sprintf (path, "%s\\*.*", GetCtrlrDir());

		hFind = FindFirstFile(path, &FindFileData);

	    if (hFind != INVALID_HANDLE_VALUE)
		{
			do 
			{
				if (strcmp (FindFileData.cFileName,".") != 0 && 
					strcmp (FindFileData.cFileName,"..") != 0)
				{
					// copy the filename
					strcpy (root,FindFileData.cFileName);

					// assume it's not a zip file
					isZipFile = 0;

					// find the extension
					ext = strrchr (root,'.');
					if (ext)
					{
						// check if it's a zip file
						if (strcmp (ext, ".zip") == 0)
						{
							isZipFile = 1;
						}

						// and strip off the extension
						*ext = 0;
					}

					if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || isZipFile)
					{
						ComboBox_AddString(hCtrl, root);
					}
				}
			}
			while (FindNextFile (hFind, &FindFileData) != 0);
			
			FindClose (hFind);
		}
	}
}

/* Populate the effect drop down */
static void InitializeEffectUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_EFFECT);

	if (hCtrl)
	{
		int i;
		for (i = 0; i < NUMEFFECTS; i++)
		{
			ComboBox_InsertString(hCtrl, i, win32_getstring(WIN32_property_none + i));
			ComboBox_SetItemData( hCtrl, i, g_ComboBoxEffect[i].m_pData);
		}
	}
}

/* Populate the BIOS type drop down */
static void InitializeBiosUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_BIOSTYPE);

	if (hCtrl)
	{
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_standardBIOS));   /* 0 */
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_debugBIOS));      /* 1 */
	}
}

/* Populate the window size drop down */
static void InitializeWindowSizeUI(HWND hwnd)
{
	HWND hCtrl = GetDlgItem(hwnd, IDC_WINDOWSIZE);

	if (hCtrl)
	{
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_size1x));   /* 0 */
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_size2x));   /* 1 */
		ComboBox_AddString(hCtrl, win32_getstring(WIN32_property_sizemax));  /* 2 */
	}
}

/* Populate the Joystick ID drop down */
static void InitializeJoyidUI(HWND hWnd)
{
	HWND hCtrl;
	int i, j, num;
	char buf[8];

	if (DIJoystick.Available() == FALSE)
		return;

	if (GetJoyGUI() == FALSE)
		DIJoystick.init();

	num = (DIJoystick_GetNumPhysicalJoysticks() < 4) ? DIJoystick_GetNumPhysicalJoysticks() : 4;

	for (i = 0; i < num; i++)
	{
		hCtrl = GetDlgItem(hWnd, IDC_JOYID1 + i);
		if (hCtrl)
		{
			for (j = 0;j < DIJoystick_GetNumPhysicalJoysticks(); j++)
			{
				sprintf(buf, "ID:%d", j + 1);
				ComboBox_AddString(hCtrl, buf);
			}
		}
	}
}

/**************************************************************************
    Game History functions
 **************************************************************************/

/* Load indexes from history.dat if found */
char * GameHistory(int game_index)
{
	historyBuf[0] = '\0';

	if (load_driver_history(drivers[game_index], historyBuf, sizeof(historyBuf)) == 0)
		HistoryFixBuf(historyBuf);

	return historyBuf;
}

static void HistoryFixBuf(char *buf)
{
	char *s  = tempHistoryBuf;
	char *p  = buf;
	int  len = 0;

	if (strlen(buf) < 3)
	{
		*buf = '\0';
		return;
	}

	while (*p && len < MAX_HISTORY_LEN - 1)
	{
		if (*p == '\n')
		{
			*s++ = '\r';
			len++;
		}

		*s++ = *p++;
		len++;
	}

	*s++ = '\0';
	strcpy(buf, tempHistoryBuf);
}

/* End of source file */
