/*==========================================================================
 *
 *  Copyright (C) 1996 Brian King
 *
 *  File:       wingui.c
 *  Content:    Win32-specific gui features for UAE port.
 *
 ***************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <windows.h>

#ifdef _MSC_VER
#include <mmsystem.h>
#include <commctrl.h>
#include <commdlg.h>
#include <dlgs.h>
#include <ddraw.h>
#include <process.h>
#include <prsht.h>
#include <richedit.h>
#include <shellapi.h>
#include <shlobj.h>
#else
#include "winstuff.h"
#endif

#include "config.h"
#include "resource.h"
#include "sysconfig.h"
#include "sysdeps.h"
#include "gui.h"
#include "options.h"
#include "include/memory.h"
#include "custom.h"
#include "readcpu.h"
#include "newcpu.h"
#include "disk.h"
#include "uae.h"
#include "autoconf.h"

#include "picasso96.h"
#include "osdep/win32gui.h"
#include "osdep/win32.h"
#include "sounddep/sound.h"
#include "target.h"

static int allow_quit;
static int full_property_sheet;
static struct uae_prefs *pguiprefs;
static struct uae_prefs workprefs;
static struct uaedev_mount_info *work_mountinfo;

extern int use_direct_sound;
extern BOOL running_winnt;
extern HINSTANCE hInst;
extern HWND hAmigaWnd;
extern uae_u8 julian_mode;

extern int mouseactive;
extern char *start_path;
extern int joystickspresent[MAXJOYSTICKS];
extern RGBFTYPE figure_pixel_formats( RGBFTYPE colortype );

char config_filename[ MAX_PATH ] = "";

HANDLE win32uae_key = NULL;

drive_specs blankdrive =
{"", "", 1, 32, 1, 2, 0, 0};

#define Error(x) MessageBox( NULL, (x), "WinUAE Error", MB_OK )

HWND hPropertySheet = NULL;

/* C_PAGES must be last */
enum {
    LOADSAVE_ID, MEMORY_ID, KICKSTART_ID, CPU_ID,
    DISPLAY_ID, SOUND_ID, FLOPPY_ID, HARDDISK_ID,
    PORTS_ID, MISC_ID, ABOUT_ID, C_PAGES
};

#define MIN_CHIP_MEM 0
#define MAX_CHIP_MEM 4
#define MIN_FAST_MEM 0
#define MAX_FAST_MEM 4
#define MIN_SLOW_MEM 0
#define MAX_SLOW_MEM 2
#define MIN_Z3_MEM 0
#define MAX_Z3_MEM 11
#define MIN_P96_MEM 0
#define MAX_P96_MEM 4
#define MIN_M68K_PRIORITY 1
#define MAX_M68K_PRIORITY 16
#define MIN_REFRESH_RATE 1
#define MAX_REFRESH_RATE 10

#define MAX_LINES 580

/* direction - 0 is workprefs --> pguiprefs
 *             1 is pguiprefs --> workprefs
 */
static void transfer_prefs( int direction )
{
    struct uaedev_mount_info *oldmi;

    if( direction == 0 )
    {
        oldmi = pguiprefs->mountinfo;
        *pguiprefs = workprefs;
        if( oldmi != workprefs.mountinfo )
        {
            free_mountinfo( oldmi );
            currprefs.mountinfo = workprefs.mountinfo;
        }
        else
            free_mountinfo( work_mountinfo );
        work_mountinfo = dup_mountinfo( workprefs.mountinfo );
    }
    else
    {
        oldmi = workprefs.mountinfo;
        workprefs = *pguiprefs;
        if( oldmi != pguiprefs->mountinfo )
        {
            free_mountinfo( oldmi );
            workprefs.mountinfo = currprefs.mountinfo;
        }
        else
            free_mountinfo( work_mountinfo );
        work_mountinfo = dup_mountinfo( currprefs.mountinfo );
    }
}

static void CreateDiskFile (char *name)
{
    HANDLE adf;
    int i, file_size = 880 * 1024;
    char *chunk = NULL;
    DWORD count;

    SetCursor (LoadCursor (NULL, IDC_WAIT));
    adf = CreateFile (name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
    if (adf != INVALID_HANDLE_VALUE) {
	if ((chunk = malloc (10240)) != NULL) {
	    for (i = 0; i < file_size; i += 10240) {
		WriteFile (adf, chunk, 10240, &count, NULL);
	    }
	}
	CloseHandle (adf);
    }
    SetCursor (LoadCursor (NULL, IDC_ARROW));
}

// Common routine for popping up a file-requester
// flag - 0 for floppy loading, 1 for floppy creation, 2 for loading hdf, 3 for saving hdf
// flag - 4 for loading .uae config-files, 5 for saving .uae config-files
// flag = 6 for loading .rom files, 7 for loading .key files
void DiskSelection( HWND hDlg, WPARAM wParam, int flag, struct uae_prefs *prefs )
{
    OPENFILENAME openFileName;
    char regfloppypath[MAX_PATH] = "";
    char regrompath[MAX_PATH] = "";
    DWORD dwType = REG_SZ;
    DWORD dwRFPsize = MAX_PATH;
    DWORD dwRRPsize = MAX_PATH;

    char full_path[MAX_PATH] = "";
    char file_name[MAX_PATH] = "";
    char init_path[MAX_PATH] = "";
    BOOL result = FALSE;
    char *amiga_path = NULL;
    char description[ CFG_DESCRIPTION_LENGTH ] = "";

    if( hWinUAEKey )
    {
        RegQueryValueEx( hWinUAEKey, "FloppyPath", 0, &dwType, (LPBYTE)regfloppypath, &dwRFPsize );
        RegQueryValueEx( hWinUAEKey, "KickstartPath", 0, &dwType, (LPBYTE)regrompath, &dwRRPsize );
    }

    if( start_path ) 
    {
	    strncpy( init_path, start_path, MAX_PATH );
	    if( flag == 2 || flag == 3 )
        {
	        strncat( init_path, "\\..\\shared\\hdf\\", MAX_PATH );
        }
	    else if( flag == 4 || flag == 5 )
        {
	        strncat( init_path, "\\Configurations\\", MAX_PATH );
        }
        else if( flag == 6 || flag == 7 )
        {
            if( regrompath[0] )
                strncpy( init_path, regrompath, MAX_PATH );
        }
        else if( regfloppypath[0] )
        {
            strncpy( init_path, regfloppypath, MAX_PATH );
        }
    }
    openFileName.lStructSize = sizeof (OPENFILENAME);
    openFileName.hwndOwner = hDlg;
    openFileName.hInstance = hInst;
    switch (flag) {
     case 0:
	openFileName.lpstrTitle = "Select an Amiga Disk File image...";
	openFileName.lpstrDefExt = "ADF";
	openFileName.lpstrFilter = "Amiga Disk Files (*.ADF;*.ADZ;*.DMS)\0*.ADF;*.ADZ;*.DMS\0";
	break;
     case 1:
	openFileName.lpstrTitle = "Choose your blank Amiga Disk File...";
	openFileName.lpstrDefExt = "ADF";
	openFileName.lpstrFilter = "Amiga Disk Files (*.ADF)\0*.ADF\0";
	break;
     case 2:
     case 3:
	openFileName.lpstrTitle = "Select a Hard Disk File...";
	openFileName.lpstrDefExt = "HDF";
	openFileName.lpstrFilter = "Hard Disk Files (*.HDF)\0*.HDF\0";
	break;
     case 4:
     case 5:
         openFileName.lpstrTitle  = "Select a UAE Config-File...";
         openFileName.lpstrDefExt = "UAE";
         openFileName.lpstrFilter = "UAE Config Files (*.UAE)\0*.UAE\0";
         break;
     case 6:
        openFileName.lpstrTitle = "Select an Amiga ROM file...";
        openFileName.lpstrDefExt = "ROM";
        openFileName.lpstrFilter = "Amiga Kickstart Files (*.ROM)\0*.ROM\0\0";
        break;
     case 7:
	    openFileName.lpstrTitle = "Select an Amiga Key-File...";
        openFileName.lpstrFilter = "Amiga Kickstart Key-Files (*.KEY)\0*.KEY\0\0";
	    openFileName.lpstrDefExt = "KEY";
        break;
    }
    openFileName.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_LONGNAMES | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
    openFileName.lpstrCustomFilter = NULL;
    openFileName.nMaxCustFilter = 0;
    openFileName.nFilterIndex = 0;
    openFileName.lpstrFile = full_path;
    openFileName.nMaxFile = MAX_PATH;
    openFileName.lpstrFileTitle = file_name;
    openFileName.nMaxFileTitle = MAX_PATH;
    if (start_path)
	openFileName.lpstrInitialDir = init_path;
    else
	openFileName.lpstrInitialDir = NULL;
    openFileName.lpfnHook = NULL;
    openFileName.lpTemplateName = NULL;
    openFileName.lCustData = 0;
    if (flag == 1 || flag == 3 || flag == 5)
	    result = GetSaveFileName (&openFileName);
    else
	    result = GetOpenFileName (&openFileName);

    if (result == FALSE)
	    write_log ("GetOpenFileName() failed.\n");
    else 
    {
	    switch (wParam) 
        {
            case IDC_PATH_NAME:
	            SetDlgItemText (hDlg, wParam, full_path);
            break;
            case IDC_DF0:
	            SetDlgItemText (hDlg, IDC_DF0TEXT, full_path);
                strcpy( prefs->df[0], full_path );
                disk_insert( 0, full_path );
            break;
            case IDC_DF1:
	            SetDlgItemText (hDlg, IDC_DF1TEXT, full_path);
                strcpy( prefs->df[1], full_path );
                disk_insert( 1, full_path );
            break;
            case IDC_DF2:
	            SetDlgItemText (hDlg, IDC_DF2TEXT, full_path);
                strcpy( prefs->df[2], full_path );
                disk_insert( 2, full_path );
            break;
            case IDC_DF3:
	            SetDlgItemText (hDlg, IDC_DF3TEXT, full_path);
                strcpy( prefs->df[3], full_path );
                disk_insert( 3, full_path );
            break;
            case IDC_CREATE:
                CreateDiskFile (full_path);
            break;
            case IDC_LOAD:
                cfgfile_get_description( full_path, description );
                SetDlgItemText( hDlg, IDC_EDITDESCRIPTION, description );
                SetDlgItemText( hDlg, IDC_EDITNAME, full_path );
            break;
            case IDC_SAVE:
                SetDlgItemText( hDlg, IDC_EDITNAME, full_path );
            break;
            case IDC_ROMFILE:
                SetDlgItemText( hDlg, IDC_ROMFILE, full_path );
                strcpy( workprefs.romfile, full_path );
                break;
            case IDC_KEYFILE:
                SetDlgItemText( hDlg, IDC_KEYFILE, full_path );
                strcpy( workprefs.keyfile, full_path );
                break;
        }
        if( flag == 0 || flag == 1 )
        {
            amiga_path = strstr( openFileName.lpstrFile, openFileName.lpstrFileTitle );
            if( amiga_path && amiga_path != openFileName.lpstrFile )
            {
                *amiga_path = 0;
                if( hWinUAEKey )
                    RegSetValueEx( hWinUAEKey, "FloppyPath", 0, REG_SZ, (CONST BYTE *)openFileName.lpstrFile, strlen( openFileName.lpstrFile ) );
            }
        }
        else if( flag == 6 || flag == 7 )
        {
            amiga_path = strstr( openFileName.lpstrFile, openFileName.lpstrFileTitle );
            if( amiga_path && amiga_path != openFileName.lpstrFile )
            {
                *amiga_path = 0;
                if( hWinUAEKey )
                    RegSetValueEx( hWinUAEKey, "KickstartPath", 0, REG_SZ, (CONST BYTE *)openFileName.lpstrFile, strlen( openFileName.lpstrFile ) );
            }
        }
    }
}

static BOOL CreateHardFile (HWND hDlg, UINT hfsize)
{
    HANDLE hf;
    int i = 0;
    BOOL result = FALSE;

    char init_path[MAX_PATH] = "";

    DiskSelection (hDlg, IDC_PATH_NAME, 3, &workprefs);
    GetDlgItemText (hDlg, IDC_PATH_NAME, init_path, MAX_PATH);
    if( *init_path && hfsize ) 
    {
	    SetCursor( LoadCursor( NULL, IDC_WAIT ) );
	    if( ( hf = CreateFile (init_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL) ) != INVALID_HANDLE_VALUE )
        {
            if( SetFilePointer( hf, hfsize, NULL, FILE_BEGIN ) == hfsize )
            {
                result = SetEndOfFile( hf );
            }
            else
            {
                write_log( "SetFilePointer() failure for %s to posn %d\n", init_path, hfsize );
            }
            CloseHandle( hf );
        }
        else
        {
            write_log( "CreateFile() failed to create %s\n", init_path );
        }
    	SetCursor( LoadCursor( NULL, IDC_ARROW ) );
    }
    return result;
}

static const char *memsize_names[] = {
    "None",
    "256 K",
    "512 K",
    "1 MB",
    "2 MB",
    "4 MB",
    "8 MB",
    "16 MB",
    "32 MB",
    "64 MB",
    "128 MB",
    "256 MB",
    "512 MB",
    "1 GB"
};

static unsigned long memsizes[] = {
    0,
    0x00040000,
    0x00080000,
    0x00100000,
    0x00200000,
    0x00400000,
    0x00800000,
    0x01000000,
    0x02000000,
    0x04000000,
    0x08000000,
    0x10000000,
    0x20000000,
    0x40000000
};

static int msi_chip[] = { 2, 3, 4, 5, 6, 7 };
static int msi_bogo[] = { 0, 2, 3 };
static int msi_fast[] = { 0, 3, 4, 5, 6 };
static int msi_z3fast[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
static int msi_gfx[] = { 0, 3, 4, 5, 6 };

static HWND pages[C_PAGES];

static UINT CalculateHardfileSize (HWND hDlg)
{
    BOOL Translated = FALSE;
    UINT bytes = 0;
    bytes = GetDlgItemInt( hDlg, IDC_HFSIZE, &Translated, FALSE );
    if( !Translated )
        bytes = 0;
    return bytes;
}


static const char *nth[] = {
    "", "second ", "third ", "fourth ", "fifth ", "sixth ", "seventh ", "eighth ", "ninth ", "tenth "
};

ConfigStructPtr AllocateConfigStruct( void )
{
    return malloc( sizeof( ConfigStruct ) );
}

void FreeConfigStruct( ConfigStructPtr cfgptr )
{
    free( cfgptr );
}

ConfigStructPtr GetFirstConfigEntry( HANDLE *file_handle, LPWIN32_FIND_DATA find_data )
{
    ConfigStructPtr config = NULL;
    DWORD num_bytes = 0;
    char init_path[ MAX_PATH ] = "", *posn;
    char description[ CFG_DESCRIPTION_LENGTH ] = "";

    if( start_path )
    {
        strncpy( init_path, start_path, MAX_PATH );
        strncat( init_path, "\\Configurations\\*.UAE", MAX_PATH );
    }

    if( ( *file_handle = FindFirstFile( init_path, find_data ) ) != INVALID_HANDLE_VALUE )
    {
        config = AllocateConfigStruct();
        sprintf( init_path, "%s\\Configurations\\%s", start_path, find_data->cFileName );
        if( cfgfile_get_description( init_path, description ) )
        {
            if( ( posn = strrchr( find_data->cFileName, '.' ) ) != NULL )
                *posn = '\0';
            strcpy( config->Name, find_data->cFileName );

            strcpy( config->Description, description );
        }
        else
        {
            FreeConfigStruct( config );
            config = NULL;
        }
    }
    else
    {
        // Either the directory has no .CFG files, or doesn't exist.

        // Create the directory, even if it already exists.  No harm, and don't check return codes, because
        // we may be doing this on a read-only media like CD-ROM.
        sprintf( init_path, "%s\\Configurations", start_path );
        CreateDirectory( init_path, NULL );
    }
    return config;
}

ConfigStructPtr GetNextConfigEntry( HANDLE *file_handle, LPWIN32_FIND_DATA find_data )
{
    ConfigStructPtr config = NULL;
    char init_path[ MAX_PATH ] = "";
    char desc[ CFG_DESCRIPTION_LENGTH ] = "";
    char *posn;

    if( FindNextFile( *file_handle, find_data ) == 0 )
    {
        FindClose( *file_handle );
    }
    else
    {
        config = AllocateConfigStruct();
        sprintf( init_path, "%s\\Configurations\\%s", start_path, find_data->cFileName );
        if( cfgfile_get_description( init_path, desc ) )
        {
            if( ( posn = strrchr( find_data->cFileName, '.' ) ) != NULL )
                *posn = '\0';
            strcpy( config->Name, find_data->cFileName );

            strcpy( config->Description, desc );
        }
        else
        {
            FreeConfigStruct( config );
            config = NULL;
        }
    }
    return config;
}

void HandleConfiguration( HWND hDlg, int flag )
{
    char full_path[MAX_PATH] = "";
    char file_name[MAX_PATH] = "";
    char init_path[MAX_PATH] = "";
    ConfigStructPtr cfgptr = NULL;
    int i;

    if( ( cfgptr = AllocateConfigStruct() ) != NULL )
    {
        switch( flag )
        {
            case CONFIG_SAVE_FULL:
                DiskSelection( hDlg, IDC_SAVE, 5, &workprefs );
                GetDlgItemText( hDlg, IDC_EDITNAME, full_path, MAX_PATH );
                GetDlgItemText( hDlg, IDC_EDITDESCRIPTION, workprefs.description, 256 );
                cfgfile_save( &workprefs, full_path );
            break;

            case CONFIG_LOAD_FULL:
                DiskSelection( hDlg, IDC_LOAD, 4, &workprefs );
                for( i = 0; i < C_PAGES; i++ )
                {
                    if( pages[i] )
	                    SendMessage( pages[i], WM_USER, 0, 0 );
                }
            break;
            
            case CONFIG_SAVE:
                GetDlgItemText( hDlg, IDC_EDITNAME, cfgptr->Name, MAX_PATH );
                if( cfgptr->Name[0] == '\0' )
                {
                    MessageBox( hDlg, "You must enter a name for your configuration before selecting Save...", "Save Error", MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND );
                }
                else
                {
                    if( !strchr( cfgptr->Name, '\\' ) && !strchr( cfgptr->Name, '/' ) )
                    {
                        if( start_path )
                        {
                            strncpy( init_path, start_path, MAX_PATH );
                            strncat( init_path, "\\Configurations\\", MAX_PATH );
                        }

                        sprintf( full_path, "%s%s.UAE", init_path, cfgptr->Name );
                    }
                    else
                    {
                        strcpy( full_path, cfgptr->Name );
                    }
                    GetDlgItemText( hDlg, IDC_EDITDESCRIPTION, workprefs.description, 256 );
                    cfgfile_save( &workprefs, full_path );
                }
            break;
        
            case CONFIG_LOAD:
                GetDlgItemText( hDlg, IDC_EDITNAME, cfgptr->Name, MAX_PATH );
                if( cfgptr->Name[0] == '\0' )
                {
                    MessageBox( hDlg, "You must select a configuration before selecting Load...", "Load Error", MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND );
                }
                else
                {
                    if( start_path )
                    {
                        strncpy( init_path, start_path, MAX_PATH );
                        strncat( init_path, "\\Configurations\\", MAX_PATH );
                    }

                    sprintf( full_path, "%s%s.UAE", init_path, cfgptr->Name );
                    strcpy( config_filename, cfgptr->Name );

                    if( cfgfile_load( &workprefs, full_path ) == 0 )
                    {
                        gui_message( "Could not load selected configuration!\n" );
                    }

                    for( i = 0; i < C_PAGES; i++ )
                    {
                        if( pages[i] )
	                        SendMessage( pages[i], WM_USER, 0, 0 );
                    }
                }
            break;

            case CONFIG_DELETE:
                GetDlgItemText( hDlg, IDC_EDITNAME, cfgptr->Name, MAX_PATH );
                if( cfgptr->Name[0] == '\0' )
                {
                    MessageBox( hDlg, "You must select a configuration before selecting Delete...", "Delete Error", MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND );
                }
                else
                {
                    if( MessageBox( hDlg, "Are you sure you want to Delete this configuration?", "Confirm Delete",
                                    MB_YESNO | MB_ICONWARNING | MB_APPLMODAL | MB_SETFOREGROUND ) == IDYES )
                    {
                        if( start_path )
                        {
                            strncpy( init_path, start_path, MAX_PATH );
                            strncat( init_path, "\\Configurations\\", MAX_PATH );
                        }

                        sprintf( full_path, "%s%s.UAE", init_path, cfgptr->Name );
                        DeleteFile( full_path );
                    }
                }
            break;
        }
        FreeConfigStruct( cfgptr );
    }
}

#define LOADSAVE_COLUMNS 2
#define HARDDISK_COLUMNS 7

void InitializeListView( HWND hDlg )
{
    HANDLE file_handle = NULL;
    WIN32_FIND_DATA find_data;
    BOOL rc = TRUE;
    HWND list;
    LV_ITEM lvstruct;
    LV_COLUMN lvcolumn;
    RECT rect;
    int num_columns = ( hDlg == pages[ LOADSAVE_ID ] ) ? LOADSAVE_COLUMNS : HARDDISK_COLUMNS;
    char column_heading[ HARDDISK_COLUMNS ][ 12 ];
    char sectors_str[6]   = "";
    char surfaces_str[6]  = "";
    char reserved_str[6]  = "";
    char blocksize_str[6] = "";
    char readwrite_str[4] = "";
    char volname_str[ MAX_PATH ] = "";
    int width = 0, column_width[ HARDDISK_COLUMNS ];
    int items = 0, result = 0, i, entry = 0, temp = 0;
    ConfigStructPtr config = NULL;
    char *volume, *rootdir;
    int size, cylinders, sectors, reserved, surfaces, readonly, blocksize;

    if( num_columns == LOADSAVE_COLUMNS )
    {
        strcpy( &column_heading[0][0], "Name" );
        strcpy( &column_heading[1][0], "Description" );
        list = GetDlgItem( hDlg, IDC_CONFIGLIST );
    }
    else
    {
        strcpy( &column_heading[0][0], "Volume" );
        strcpy( &column_heading[1][0], "Path" );
        strcpy( &column_heading[2][0], "R/W" );
        strcpy( &column_heading[3][0], "Sectors" );
        strcpy( &column_heading[4][0], "Surfaces" );
        strcpy( &column_heading[5][0], "Reserved" );
        strcpy( &column_heading[6][0], "Block Size" );
        list = GetDlgItem( hDlg, IDC_VOLUMELIST );
    }

    ListView_DeleteAllItems( list );

    for( i = 0; i < num_columns; i++ )
        column_width[i] = ListView_GetStringWidth( list, column_heading[i] ) + 15;

    // If there are no columns, then insert some
    lvcolumn.mask = LVCF_WIDTH;
    if( ListView_GetColumn( list, 1, &lvcolumn ) == FALSE )
    {
        for( i = 0; i < num_columns; i++ )
        {
            lvcolumn.mask     = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
            lvcolumn.iSubItem = i;
            lvcolumn.fmt      = LVCFMT_LEFT;
            lvcolumn.pszText  = column_heading[i];
            lvcolumn.cx       = column_width[i];
            ListView_InsertColumn( list, i, &lvcolumn );
        }
    }
    if( num_columns == LOADSAVE_COLUMNS )
    {
        if( ( config = GetFirstConfigEntry( &file_handle, &find_data ) ) != NULL )
        {
            while( config )
            {
                lvstruct.mask     = LVIF_TEXT | LVIF_PARAM;
                lvstruct.pszText  = config->Name;
                lvstruct.lParam   = 0;
                lvstruct.iItem    = entry;
                lvstruct.iSubItem = 0;
                result = ListView_InsertItem( list, &lvstruct );
                if( result != -1 )
                {
                    width = ListView_GetStringWidth( list, lvstruct.pszText ) + 15;
                    if( width > column_width[ lvstruct.iSubItem ] )
                        column_width[ lvstruct.iSubItem ] = width;

                    ListView_SetItemText( list, result, 1, config->Description );
                    width = ListView_GetStringWidth( list, config->Description ) + 15;
                    if( width > column_width[ 1 ] )
                        column_width[ 1 ] = width;

                    entry++;
                }
                FreeConfigStruct( config );
                config = GetNextConfigEntry( &file_handle, &find_data );
            }
        }
    }
    else
    {
        for( i = 0; i < nr_units( workprefs.mountinfo ); i++ )
        {
            get_filesys_unit (workprefs.mountinfo, i, &volume, &rootdir, &readonly,
		              &sectors, &surfaces, &reserved, &blocksize, &cylinders, &size);

            if( is_hardfile( workprefs.mountinfo, i ) )
            {
                sprintf( sectors_str, "%d", sectors );
                sprintf( surfaces_str, "%d", surfaces );
                sprintf( reserved_str, "%d", reserved );
                sprintf( blocksize_str, "%d", blocksize );
                sprintf( volname_str, "DH%d", i );
            }
            else
            {
                strcpy( sectors_str, "n/a" );
                strcpy( surfaces_str, "n/a" );
                strcpy( reserved_str, "n/a" );
                strcpy( blocksize_str, "n/a" );
                strcpy( volname_str, volume );
            }

            sprintf( readwrite_str, "%s", readonly ? "no":"yes" );
            lvstruct.mask     = LVIF_TEXT | LVIF_PARAM;
            lvstruct.pszText  = volname_str;
            lvstruct.lParam   = 0;
            lvstruct.iItem    = i;
            lvstruct.iSubItem = 0;
            result = ListView_InsertItem( list, &lvstruct );
            if( result != -1 )
            {
                width = ListView_GetStringWidth( list, lvstruct.pszText ) + 15;
                if( width > column_width[ lvstruct.iSubItem ] )
                    column_width[ lvstruct.iSubItem ] = width;

                ListView_SetItemText( list, result, 1, rootdir );
                width = ListView_GetStringWidth( list, rootdir ) + 15;
                if( width > column_width[ 1 ] )
                    column_width[ 1 ] = width;

                ListView_SetItemText( list, result, 2, readwrite_str );
                width = ListView_GetStringWidth( list, readwrite_str ) + 15;
                if( width > column_width[ 2 ] )
                    column_width[ 2 ] = width;

                ListView_SetItemText( list, result, 3, sectors_str );
                width = ListView_GetStringWidth( list, sectors_str ) + 15;
                if( width > column_width[ 3 ] )
                    column_width[ 3 ] = width;

                ListView_SetItemText( list, result, 4, surfaces_str );
                width = ListView_GetStringWidth( list, surfaces_str ) + 15;
                if( width > column_width[ 4 ] )
                    column_width[ 4 ] = width;

                ListView_SetItemText( list, result, 5, reserved_str );
                width = ListView_GetStringWidth( list, reserved_str ) + 15;
                if( width > column_width[ 5 ] )
                    column_width[ 5 ] = width;

                ListView_SetItemText( list, result, 6, blocksize_str );
                width = ListView_GetStringWidth( list, blocksize_str ) + 15;
                if( width > column_width[ 6 ] )
                    column_width[ 6 ] = width;
            }
            if( volume )
                free( volume );
            if( rootdir )
                free( rootdir );
        }
    }
    if( rc == FALSE )
    {
        FreeConfigStruct( config );
    }

    if( result != -1 )
    {
        if( GetWindowRect( list, &rect ) )
        {
            ScreenToClient( hDlg, (LPPOINT)&rect );
            ScreenToClient( hDlg, (LPPOINT)&rect.right );
            if( num_columns == 2 )
            {
                if( ( temp = rect.right - rect.left - column_width[ 0 ] - 4 ) > column_width[1] )
                    column_width[1] = temp;
            }
        }

        // Adjust our column widths so that we can see the contents...
        for( i = 0; i < num_columns; i++ )
        {
            ListView_SetColumnWidth( list, i, column_width[i] );
        }

        // Turn on full-row-select option
        ListView_SetExtendedListViewStyle( list, LVS_EX_FULLROWSELECT );
#if 0
        if( num_columns > 2 )
        {
            // Hilite the current selected item
            ListView_SetItemState( list, clicked_entry, LVIS_SELECTED, LVIS_SELECTED );
        }
#endif
        // Redraw the items in the list...
        items = ListView_GetItemCount( list );
        ListView_RedrawItems( list, 0, items );
    }
}

static int listview_find_selected (HWND list)
{
    int i, items;
    items = ListView_GetItemCount (list);
    for (i = 0; i < items; i++) {
	if (ListView_GetItemState (list, i, LVIS_SELECTED) == LVIS_SELECTED)
	    return i;
    }
    return -1;
}

static int listview_entry_from_click (HWND list)
{
    POINT point;
    DWORD pos = GetMessagePos ();
    int items, entry;

    point.x = LOWORD (pos);
    point.y = HIWORD (pos);
    ScreenToClient (list, &point);
    entry = ListView_GetTopIndex (list);
    items = entry + ListView_GetCountPerPage (list);
    if (items > ListView_GetItemCount (list))
	items = ListView_GetItemCount (list);

    while (entry <= items) {
	RECT rect;
	/* Get the bounding rectangle of an item. If the mouse
	 * location is within the bounding rectangle of the item,
	 * you know you have found the item that was being clicked.  */
	ListView_GetItemRect (list, entry, &rect, LVIR_BOUNDS);
	if (PtInRect (&rect, point)) {
	    UINT flag = LVIS_SELECTED | LVIS_FOCUSED;
	    ListView_SetItemState (list, entry, flag, flag);
	    return entry;
	}
	entry++;
    }
    return -1;
}

static BOOL CALLBACK LoadSaveDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    char name_buf[MAX_PATH] = "", desc_buf[128] = "";
    HWND list;
    int dblclick = 0;
    NM_LISTVIEW *nmlistview;
    int items = 0, entry = 0;
    LPHELPINFO lpHelpInfo;

    switch (msg) {
     case WM_INITDIALOG:
	pages[LOADSAVE_ID] = hDlg;
    InitializeListView(hDlg);
	if (! full_property_sheet) {
	    EnableWindow (GetDlgItem (hDlg, IDC_SAVE), FALSE);
	}
    SetDlgItemText( hDlg, IDC_EDITNAME, config_filename );
    SetDlgItemText( hDlg, IDC_EDITDESCRIPTION, workprefs.description );
	return TRUE;

     case WM_USER:
	break;

    case WM_HELP:
        lpHelpInfo = (LPHELPINFO)lParam;
        break;

    case WM_COMMAND:
        switch (wParam) 
        {
        case IDC_SAVE:
            HandleConfiguration( hDlg, CONFIG_SAVE_FULL );
            InitializeListView( hDlg );
        break;
        case IDC_QUICKSAVE:
            HandleConfiguration( hDlg, CONFIG_SAVE );
            InitializeListView( hDlg );
	    break;
        case IDC_QUICKLOAD:
            HandleConfiguration( hDlg, CONFIG_LOAD );
            break;
        case IDC_LOAD:
            HandleConfiguration( hDlg, CONFIG_LOAD_FULL );
            break;
	     case IDC_DELETE:
             HandleConfiguration( hDlg, CONFIG_DELETE );
             InitializeListView( hDlg );
	        break;
	    }
	break;

     case WM_NOTIFY:
	if (((LPNMHDR) lParam)->idFrom == IDC_CONFIGLIST) {
	    nmlistview = (NM_LISTVIEW *) lParam;
	    list = nmlistview->hdr.hwndFrom;

	    switch (nmlistview->hdr.code) {
	    case NM_DBLCLK:
		dblclick = 1;
		/* fall-through */
	    case NM_CLICK:
		entry = listview_entry_from_click (list);
		/* Copy the item's name and description to the gadgets at the bottom... */
		if (entry >= 0) {
		    ListView_GetItemText (list, entry, 0, name_buf, MAX_PATH);
		    ListView_GetItemText (list, entry, 1, desc_buf, 128);
		    SetDlgItemText (hDlg, IDC_EDITNAME, name_buf);
		    SetDlgItemText (hDlg, IDC_EDITDESCRIPTION, desc_buf);
		    ListView_RedrawItems (list, 0, items);

		    if( dblclick ) 
            {
                HandleConfiguration( hDlg, CONFIG_LOAD );
                /* Copy stuff from workprefs and config_xxx settings */
                transfer_prefs(0);
                PropSheet_PressButton( hPropertySheet, PSBTN_OK );
		    }
		}
		break;
	    }
	} else {
	    switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);

	    break;

        case PSN_RESET:
		if (allow_quit) {
		    quit_program = 1;
		    regs.spcflags |= SPCFLAG_BRK;
		}
		break;
	    }
	}
	break;
    }

    return FALSE;
}

static int CALLBACK ContributorsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    CHARFORMAT CharFormat;

    switch (msg) {
     case WM_COMMAND:
	if (wParam == ID_OK) {
	    EndDialog (hDlg, 1);
	    return TRUE;
	}
	break;
     case WM_INITDIALOG:
	CharFormat.cbSize = sizeof (CharFormat);

	SetDlgItemText (hDlg, IDC_CONTRIBUTORS,
			"Bernd Schmidt - The Grand-Master\n"
			"Mathias Ortmann - WinUAE Main Guy\n"
			"Brian King - Picasso96 Support, Integrated GUI for WinUAE, AHI (Working on it)\n"
            "Toni Wilen - AGA, NTSC/PAL modes, chipset switching, track-displays\n"
			"Gustavo Goedert/Peter Remmers/Michael Sontheimer/Tomi Hakala/Tim Gunn/Nemo Pohle - DOS Port Stuff\n"
			"Samuel Devulder/Olaf Barthel - Amiga Port\n"
			"Krister Bergman - XFree86 and OS/2 Port\n"
			"A. Blanchard/Ernesto Corvi - MacOS Port\n"
			"Christian Bauer - BeOS Port\n"
			"Ian Stephenson - NextStep Port\n"
			"Peter Teichmann - Acorn/RiscOS Port\n"
			"Stefan Reinauer - ZorroII/III AutoConfig, Serial Support\n"
			"Christian Schmitt/Chris Hames - Serial Support\n"
			"Herman ten Brugge - 68020/68881 Emulation Code\n"
			"Tauno Taipaleenmaki - Various UAE-Control/UAE-Library Support\n"
			"Brett Eden/Tim Gunn/Paolo Besser/Nemo Pohle - Various Docs and Web-Sites\n"
			"Special thanks to Alexander Kneer and Tobias Abt (The Picasso96 Team)");

	SendDlgItemMessage (hDlg, IDC_CONTRIBUTORS, EM_GETCHARFORMAT, 0, (LPARAM) & CharFormat);
	CharFormat.dwMask |= CFM_SIZE | CFM_FACE;
	CharFormat.yHeight = 10 * 20;	/* height in twips, where a twip is 1/20th of a point - for a pt.size of 18 */

	strcpy (CharFormat.szFaceName, "Times New Roman");
	SendDlgItemMessage (hDlg, IDC_CONTRIBUTORS, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) & CharFormat);
	/* SendDlgItemMessage(hDlg, IDC_CONTRIBUTORS, EM_SETBKGNDCOLOR,0,GetSysColor( COLOR_3DFACE ) ); */

	return TRUE;
    }
    return FALSE;
}

static void DisplayContributors (HWND hDlg)
{
    DialogBox (hInst, MAKEINTRESOURCE (IDD_CONTRIBUTORS), hDlg, ContributorsProc);
}

static void url_handler(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
#define NUM_URLS 6
    static int ids[NUM_URLS] = { IDC_CLOANTOHOME, IDC_AMIGAHOME, IDC_PICASSOHOME, IDC_UAEHOME, IDC_WINUAEHOME, IDC_AIABHOME };
    static const char *urls[NUM_URLS] = {
	"http://www.cloanto.com/amiga/forever/",
	"http://www.amiga.com",
	"http://www.picasso96.cogito.de/", 
	"http://www.freiburg.linux.de/~uae/",
	"http://www.CodePoet.com/UAE/",
    "http://www.classicgaming.com/aiab/",
    };
    static int cursor_state = 0;
    int i;
    POINT point;
    point.x = LOWORD (lParam);
    point.y = HIWORD (lParam);

    for (i = 0; i < NUM_URLS; i++) 
    {
	    RECT rect;

	    GetWindowRect (GetDlgItem (hDlg, ids[i]), &rect);
	    ScreenToClient (hDlg, (POINT *) & rect);
	    ScreenToClient (hDlg, (POINT *) & (rect.right));
	    if (PtInRect (&rect, point)) 
        {
            if( msg == WM_LBUTTONDOWN )
            {
	            ShellExecute (NULL, NULL, urls[i] , NULL, NULL, SW_SHOWNORMAL);
                //SetCursor( LoadCursor( NULL, IDC_ARROW ) );
                cursor_state = 0;
            }
            else
            {
                if( !cursor_state )
                {
                    //SetCursor( LoadCursor( hInst, IDC_HAND ) );
                    cursor_state = 1;
                }
            }
	        break;
	    }
        else if( cursor_state )
        {
            //SetCursor( LoadCursor( NULL, IDC_ARROW ) );
            cursor_state = 0;
        }
    }
}

static void SetupRichText( HWND hDlg, UINT id, char *text )
{
    CHARFORMAT CharFormat;
    CharFormat.cbSize = sizeof (CharFormat);

    SetDlgItemText( hDlg, id, text );
    SendDlgItemMessage( hDlg, id, EM_GETCHARFORMAT, 0, (LPARAM)&CharFormat );
    CharFormat.dwMask |= CFM_UNDERLINE | CFM_SIZE | CFM_FACE | CFM_COLOR;
    CharFormat.dwEffects = CFE_UNDERLINE;
    CharFormat.yHeight = 12 * 20;	/* height in twips, where a twip is 1/20th of a point - for a pt.size of 18 */

    CharFormat.crTextColor = GetSysColor( COLOR_ACTIVECAPTION );
    strcpy( CharFormat.szFaceName, "Times New Roman" );
    SendDlgItemMessage( hDlg, id, EM_SETCHARFORMAT, SCF_ALL, (LPARAM)&CharFormat );
    SendDlgItemMessage( hDlg, id, EM_SETBKGNDCOLOR, 0, GetSysColor( COLOR_3DFACE ) );
}

static void init_aboutdlg (HWND hDlg)
{
    CHARFORMAT CharFormat;
    CharFormat.cbSize = sizeof (CharFormat);

    SetDlgItemText (hDlg, IDC_RICHEDIT1, "UAE for Win32/DirectX");
    SendDlgItemMessage (hDlg, IDC_RICHEDIT1, EM_GETCHARFORMAT, 0, (LPARAM) & CharFormat);
    CharFormat.dwMask |= CFM_BOLD | CFM_SIZE | CFM_FACE;
    CharFormat.dwEffects = CFE_BOLD;
    CharFormat.yHeight = 18 * 20;	/* height in twips, where a twip is 1/20th of a point - for a pt.size of 18 */

    strcpy (CharFormat.szFaceName, "Times New Roman");
    SendDlgItemMessage (hDlg, IDC_RICHEDIT1, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) & CharFormat);
    SendDlgItemMessage (hDlg, IDC_RICHEDIT1, EM_SETBKGNDCOLOR, 0, GetSysColor (COLOR_3DFACE));

    SetDlgItemText (hDlg, IDC_RICHEDIT2, PROGNAME);
    SendDlgItemMessage (hDlg, IDC_RICHEDIT2, EM_GETCHARFORMAT, 0, (LPARAM) & CharFormat);
    CharFormat.dwMask |= CFM_SIZE | CFM_FACE;
    CharFormat.yHeight = 10 * 20;
    strcpy (CharFormat.szFaceName, "Times New Roman");
    SendDlgItemMessage (hDlg, IDC_RICHEDIT2, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) & CharFormat);
    SendDlgItemMessage (hDlg, IDC_RICHEDIT2, EM_SETBKGNDCOLOR, 0, GetSysColor (COLOR_3DFACE));

    SetupRichText( hDlg, IDC_AMIGAHOME, "Amiga Inc." );
    SetupRichText( hDlg, IDC_CLOANTOHOME, "Cloanto's Amiga Forever" );
    SetupRichText( hDlg, IDC_WINUAEHOME, "WinUAE Home Page" );
    SetupRichText( hDlg, IDC_AIABHOME, "" ); // "Amiga In A Box"
    SetupRichText( hDlg, IDC_UAEHOME, "UAE Home Page" );
    SetupRichText( hDlg, IDC_PICASSOHOME, "Picasso96 Home Page" );
}

static BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
     case WM_INITDIALOG:
	pages[ABOUT_ID] = hDlg;
	init_aboutdlg (hDlg);
	break;

     case WM_COMMAND:
	if (wParam == IDC_CONTRIBUTORS) {
	    DisplayContributors (hDlg);
	}
	break;
    case WM_LBUTTONDOWN:
    case WM_MOUSEMOVE:
	    url_handler( hDlg, msg, wParam, lParam );
	break;
     case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;

    case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
	break;
    }

    return FALSE;
}

static struct win32_displaymode *GetDisplayMode (int logical_number)
{
    struct win32_displaymode *dm = win32_displaymode_list;
    while (logical_number > 0 && dm != 0)
	dm = dm->next, logical_number--;
    return dm;
}

static void enable_for_displaydlg (HWND hDlg)
{
    if (! full_property_sheet) 
    {
	    /* Disable certain controls which are only to be set once at start-up... */
        EnableWindow (GetDlgItem (hDlg, IDC_TEST16BIT), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_LORES), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_XCENTER), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_YCENTER), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_ASPECT), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_LM_NORMAL), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_LM_DOUBLED), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_LM_SCANLINES), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_RESOLUTION), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_XSIZE), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_YSIZE), FALSE);
        EnableWindow (GetDlgItem (hDlg, IDC_NTSC), FALSE);
        EnableWindow (GetDlgItem (hDlg, IDC_OCS), FALSE);
        EnableWindow (GetDlgItem (hDlg, IDC_ECS_AGNUS), FALSE);
        EnableWindow (GetDlgItem (hDlg, IDC_ECS_DENISE), FALSE);
        EnableWindow (GetDlgItem (hDlg, IDC_ECS), FALSE);
        EnableWindow (GetDlgItem (hDlg, IDC_AGA), FALSE);
    }
    else
    {
        EnableWindow (GetDlgItem (hDlg, IDC_PFULLSCREEN), ! workprefs.address_space_24);
        EnableWindow( GetDlgItem( hDlg, IDC_XSIZE ), workprefs.gfx_afullscreen ? FALSE:TRUE );
        EnableWindow( GetDlgItem( hDlg, IDC_YSIZE ), workprefs.gfx_afullscreen ? FALSE:TRUE );
        EnableWindow( GetDlgItem( hDlg, IDC_RESOLUTION ), workprefs.gfx_afullscreen ? TRUE:FALSE );
    }
}

static void values_to_displaydlg (HWND hDlg)
{
    char buffer[40];
    int d,d2,index;

    switch( workprefs.color_mode )
    {
    case 2:
        d = 16;
        break;
    case 5:
        d = 32;
        break;
    default:
        d = 8;
        break;
    }

    if( workprefs.gfx_afullscreen )
    {
        d2 = d;
        if( ( index = adjust_screenmode( &workprefs.gfx_width, &workprefs.gfx_height, &d2 ) ) >= 0 )
        {
            switch( d2 )
            {
            case 15:
                workprefs.color_mode = 1;
                d = 2;
                break;
            case 16:
                workprefs.color_mode = 2;
                d = 2;
                break;
            case 32:
                workprefs.color_mode = 5;
                d = 4;
                break;
            default:
                workprefs.color_mode = 0;
                d = 1;
                break;
            }
        }
    }
    else
    {
        d = d/8;
    }

    if( ( index = GetDisplayModeIndex( workprefs.gfx_width, workprefs.gfx_height, d ) ) >= 0 )
        SendDlgItemMessage( hDlg, IDC_RESOLUTION, CB_SETCURSEL, index, 0 );

    SetDlgItemInt( hDlg, IDC_XSIZE, workprefs.gfx_width, FALSE );
    SetDlgItemInt( hDlg, IDC_YSIZE, workprefs.gfx_height, FALSE );

    SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_SETPOS, TRUE, workprefs.framerate);
    sprintf (buffer, "Every %sFrame", nth[workprefs.framerate - 1]);
    SetDlgItemText (hDlg, IDC_RATETEXT, buffer);

    CheckRadioButton( hDlg, IDC_LM_NORMAL, IDC_LM_SCANLINES, IDC_LM_NORMAL+workprefs.gfx_linedbl );
    CheckRadioButton( hDlg, IDC_OCS, IDC_AGA, IDC_OCS+workprefs.chipset );

    CheckDlgButton (hDlg, IDC_AFULLSCREEN, workprefs.gfx_afullscreen);
    CheckDlgButton (hDlg, IDC_PFULLSCREEN, workprefs.gfx_pfullscreen);
    CheckDlgButton (hDlg, IDC_ASPECT, workprefs.gfx_correct_aspect);
    CheckDlgButton (hDlg, IDC_LORES, workprefs.gfx_lores);
    
	CheckDlgButton (hDlg, IDC_XCENTER, workprefs.gfx_xcenter);
    CheckDlgButton (hDlg, IDC_YCENTER, workprefs.gfx_ycenter);
    CheckDlgButton (hDlg, IDC_NTSC, workprefs.ntscmode);
}

static void init_resolution_combo (HWND hDlg)
{
    int i;

    for( i = 0; i < GetNumResolutions(); i++ )
    {
        SendDlgItemMessage( hDlg, IDC_RESOLUTION, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)DisplayModes[i].name );
    }
}

static void values_from_displaydlg (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    BOOL success = FALSE;
    workprefs.gfx_pfullscreen    = IsDlgButtonChecked (hDlg, IDC_PFULLSCREEN);
    workprefs.gfx_afullscreen    = IsDlgButtonChecked (hDlg, IDC_AFULLSCREEN);
    EnableWindow( GetDlgItem( hDlg, IDC_RESOLUTION ), workprefs.gfx_afullscreen ? TRUE:FALSE );

    workprefs.gfx_lores          = IsDlgButtonChecked (hDlg, IDC_LORES);
    workprefs.gfx_correct_aspect = IsDlgButtonChecked (hDlg, IDC_ASPECT);
    workprefs.gfx_linedbl = ( IsDlgButtonChecked( hDlg, IDC_LM_SCANLINES ) ? 2 :
                              IsDlgButtonChecked( hDlg, IDC_LM_DOUBLED ) ? 1 : 0 );

    workprefs.chipset = ( IsDlgButtonChecked( hDlg, IDC_OCS ) ? 0:
                          IsDlgButtonChecked( hDlg, IDC_ECS_AGNUS ) ? 1:
                          IsDlgButtonChecked( hDlg, IDC_ECS_DENISE ) ? 2:
                          IsDlgButtonChecked( hDlg, IDC_ECS ) ? 3:4 );

    workprefs.framerate = SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_GETPOS, 0, 0);

    {
	    char buffer[40];
	    sprintf (buffer, "Every %sFrame", nth[workprefs.framerate - 1]);
	    SetDlgItemText (hDlg, IDC_RATETEXT, buffer);
 	    workprefs.gfx_width  = GetDlgItemInt( hDlg, IDC_XSIZE, &success, FALSE );
        if( !success )
            workprefs.gfx_width = 800;
	    workprefs.gfx_height = GetDlgItemInt( hDlg, IDC_YSIZE, &success, FALSE );
        if( !success )
            workprefs.gfx_height = 600;
    }
    workprefs.gfx_xcenter = (IsDlgButtonChecked (hDlg, IDC_XCENTER) ? 2 : 0 ); /* Smart centering */
    workprefs.gfx_ycenter = (IsDlgButtonChecked (hDlg, IDC_YCENTER) ? 2 : 0 ); /* Smart centering */

    workprefs.ntscmode = (IsDlgButtonChecked (hDlg, IDC_NTSC) ? 1 : 0 );

    if (msg == WM_COMMAND && LOWORD (wParam) == IDC_RESOLUTION && HIWORD (wParam) == CBN_SELCHANGE) 
    {
	    LONG posn;
	    posn = SendDlgItemMessage (hDlg, IDC_RESOLUTION, CB_GETCURSEL, 0, 0);
	    if (posn == CB_ERR)
	        return;
        workprefs.gfx_width  = DisplayModes[posn].res.width;
        workprefs.gfx_height = DisplayModes[posn].res.height;
        switch( DisplayModes[posn].depth )
        {
        case 2:
            workprefs.color_mode = 2;
            break;
        case 3:
        case 4:
            workprefs.color_mode = 5;
            break;
        default:
            workprefs.color_mode = 0;
            break;
        }
        /* Set the Int boxes */
        SetDlgItemInt( hDlg, IDC_XSIZE, workprefs.gfx_width, FALSE );
        SetDlgItemInt( hDlg, IDC_YSIZE, workprefs.gfx_height, FALSE );
    }
}

static BOOL CALLBACK DisplayDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;
    HKEY hPixelFormatKey;
    RGBFTYPE colortype      = RGBFB_NONE;
    DWORD dwType            = REG_DWORD;
    DWORD dwDisplayInfoSize = sizeof( colortype );

    switch (msg) 
    {
        case WM_INITDIALOG:
	        pages[DISPLAY_ID] = hDlg;
	        SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_SETPAGESIZE, 0, 1);
	        SendDlgItemMessage (hDlg, IDC_FRAMERATE, TBM_SETRANGE, TRUE, MAKELONG (MIN_REFRESH_RATE, MAX_REFRESH_RATE));
	        init_resolution_combo( hDlg );

        case WM_USER:
	        recursive++;
	        values_to_displaydlg (hDlg);
	        enable_for_displaydlg (hDlg);
	        recursive--;
        break;

        case WM_HSCROLL:
        case WM_COMMAND:
	        if (recursive > 0)
	            break;
	        recursive++;
            if( ( wParam == IDC_TEST16BIT ) && start_ddraw() )
            {
                if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Software\\CodePoet Computing\\WinUAE", 0, KEY_ALL_ACCESS, &hPixelFormatKey ) == ERROR_SUCCESS )
                {
                    if( MessageBox( NULL, "WinUAE will now determine your graphic-card's 16-bit pixel format.  "
                                          "Your screen will go black for two seconds, with a resolution of 640x480 @ 60Hz.  "
                                          "This procedure is necessary to properly display your Amiga software on 16-bit "
                                          "display-modes, and should be done whenever you run WinUAE for the first time, or "
                                          "install a new graphics-card in your PC.  Proceed with this test?",
                                          "Pixel Format Detection", MB_YESNO | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND ) == IDYES )
                    {
                        colortype = figure_pixel_formats(0);
                        RegSetValueEx( hPixelFormatKey, "DisplayInfo", 0, REG_DWORD, (CONST BYTE *)&colortype, sizeof( colortype ) );
                    }
                    RegCloseKey( hPixelFormatKey );
                }
                else
                {
                    write_log( "WinUAE is missing HKEY_LOCAL_MACHINE Registry keys!  These can only be created by a valid Setup program.\n" );
                }
                release_ddraw();
            }
            else
            {
	            values_from_displaydlg (hDlg, msg, wParam, lParam);
                enable_for_displaydlg( hDlg );
            }
	        recursive--;
	    break;

        case WM_NOTIFY:
	        switch (((NMHDR *) lParam)->code) 
            {
	            case PSN_APPLY:
                    /* Copy stuff from workprefs and config_xxx settings */
                    transfer_prefs(0);
	            break;

                case PSN_RESET:
	                if (allow_quit) 
                    {
		                quit_program = 1;
		                regs.spcflags |= SPCFLAG_BRK;
	                }
	            break;
	        }
        break;
    }
    return FALSE;
}

static void enable_for_memorydlg (HWND hDlg)
{
    EnableWindow (GetDlgItem (hDlg, IDC_Z3TEXT), ! workprefs.address_space_24);
    EnableWindow (GetDlgItem (hDlg, IDC_Z3FASTRAM), ! workprefs.address_space_24);
    EnableWindow (GetDlgItem (hDlg, IDC_Z3FASTMEM), ! workprefs.address_space_24);
    EnableWindow (GetDlgItem (hDlg, IDC_FASTMEM), workprefs.chipmem_size <= 0x200000);
    EnableWindow (GetDlgItem (hDlg, IDC_FASTRAM), workprefs.chipmem_size <= 0x200000);
    EnableWindow (GetDlgItem (hDlg, IDC_FASTTEXT), workprefs.chipmem_size <= 0x200000);
    EnableWindow (GetDlgItem (hDlg, IDC_GFXCARDTEXT), ! workprefs.address_space_24);
    EnableWindow (GetDlgItem (hDlg, IDC_P96RAM), ! workprefs.address_space_24);
    EnableWindow (GetDlgItem (hDlg, IDC_P96MEM), ! workprefs.address_space_24);
}

static void values_to_memorydlg (HWND hDlg)
{
    uae_u32 mem_size = 0;

    switch (workprefs.chipmem_size) {
     case 0x00080000: mem_size = 0; break;
     case 0x00100000: mem_size = 1; break;
     case 0x00200000: mem_size = 2; break;
     case 0x00400000: mem_size = 3; break;
     case 0x00800000: mem_size = 4; break;
    }
    SendDlgItemMessage (hDlg, IDC_CHIPMEM, TBM_SETPOS, TRUE, mem_size);
    SetDlgItemText (hDlg, IDC_CHIPRAM, memsize_names[msi_chip[mem_size]]);

    switch (workprefs.fastmem_size) {
     case 0x00000000: mem_size = 0; break;
     case 0x00100000: mem_size = 1; break;
     case 0x00200000: mem_size = 2; break;
     case 0x00400000: mem_size = 3; break;
     case 0x00800000: mem_size = 4; break;
     case 0x01000000: mem_size = 5; break;
    }
    SendDlgItemMessage (hDlg, IDC_FASTMEM, TBM_SETPOS, TRUE, mem_size);
    SetDlgItemText (hDlg, IDC_FASTRAM, memsize_names[msi_fast[mem_size]]);

    switch (workprefs.bogomem_size) {
     case 0x00000000: mem_size = 0; break;
     case 0x00080000: mem_size = 1; break;
     case 0x00100000: mem_size = 2; break;
    }
    SendDlgItemMessage (hDlg, IDC_SLOWMEM, TBM_SETPOS, TRUE, mem_size);
    SetDlgItemText (hDlg, IDC_SLOWRAM, memsize_names[msi_bogo[mem_size]]);

    switch (workprefs.z3fastmem_size) {
     case 0x00000000: mem_size = 0; break; /*   0-megs */
     case 0x00100000: mem_size = 1; break; /*   1-megs */
     case 0x00200000: mem_size = 2; break; /*   2-megs */
     case 0x00400000: mem_size = 3; break; /*   4-megs */
     case 0x00800000: mem_size = 4; break; /*   8-megs */
     case 0x01000000: mem_size = 5; break; /*  16-megs */
     case 0x02000000: mem_size = 6; break; /*  32-megs */
     case 0x04000000: mem_size = 7; break; /*  64-megs */
     case 0x08000000: mem_size = 8; break; /* 128-megs */
     case 0x10000000: mem_size = 9; break; /* 256-megs */
     case 0x20000000: mem_size = 10; break;/* 512-megs */
     case 0x40000000: mem_size = 11; break;/*   1-Gig  */
    }
    SendDlgItemMessage (hDlg, IDC_Z3FASTMEM, TBM_SETPOS, TRUE, mem_size);
    SetDlgItemText (hDlg, IDC_Z3FASTRAM, memsize_names[msi_z3fast[mem_size]]);

    switch (workprefs.gfxmem_size) {
     case 0x00000000: mem_size = 0; break;
     case 0x00100000: mem_size = 1; break;
     case 0x00200000: mem_size = 2; break;
     case 0x00400000: mem_size = 3; break;
     case 0x00800000: mem_size = 4; break;
    }
    SendDlgItemMessage (hDlg, IDC_P96MEM, TBM_SETPOS, TRUE, mem_size);
    SetDlgItemText (hDlg, IDC_P96RAM, memsize_names[msi_gfx[mem_size]]);
}

static void fix_values_memorydlg (void)
{
    if (workprefs.chipmem_size > 0x200000)
	workprefs.fastmem_size = 0;
}

static BOOL CALLBACK MemoryDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;
    unsigned int max_z3_mem = MAX_Z3_MEM;
    MEMORYSTATUS memstats;

    switch (msg) {
     case WM_INITDIALOG:
	pages[MEMORY_ID] = hDlg;

    memstats.dwLength = sizeof( memstats );
    GlobalMemoryStatus( &memstats );
    while( ( memstats.dwAvailPageFile + memstats.dwAvailPhys ) < (DWORD)( 1 << (max_z3_mem + 19) ) )
        max_z3_mem--;

    SendDlgItemMessage (hDlg, IDC_CHIPMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_CHIP_MEM, MAX_CHIP_MEM));
	SendDlgItemMessage (hDlg, IDC_FASTMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_FAST_MEM, MAX_FAST_MEM));
	SendDlgItemMessage (hDlg, IDC_SLOWMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_SLOW_MEM, MAX_SLOW_MEM));
	SendDlgItemMessage (hDlg, IDC_Z3FASTMEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_Z3_MEM, max_z3_mem));
	SendDlgItemMessage (hDlg, IDC_P96MEM, TBM_SETRANGE, TRUE, MAKELONG (MIN_P96_MEM, MAX_P96_MEM));

     case WM_USER:
	recursive++;
	fix_values_memorydlg ();
	values_to_memorydlg (hDlg);
	enable_for_memorydlg (hDlg);
	recursive--;
	break;

    case WM_HSCROLL:
	workprefs.chipmem_size = memsizes[msi_chip[SendMessage (GetDlgItem (hDlg, IDC_CHIPMEM), TBM_GETPOS, 0, 0)]];
	workprefs.bogomem_size = memsizes[msi_bogo[SendMessage (GetDlgItem (hDlg, IDC_SLOWMEM), TBM_GETPOS, 0, 0)]];
	workprefs.fastmem_size = memsizes[msi_fast[SendMessage (GetDlgItem (hDlg, IDC_FASTMEM), TBM_GETPOS, 0, 0)]];
	workprefs.z3fastmem_size = memsizes[msi_z3fast[SendMessage (GetDlgItem (hDlg, IDC_Z3FASTMEM), TBM_GETPOS, 0, 0)]];
	workprefs.gfxmem_size = memsizes[msi_gfx[SendMessage (GetDlgItem (hDlg, IDC_P96MEM), TBM_GETPOS, 0, 0)]];
    fix_values_memorydlg();
    values_to_memorydlg(hDlg);
    enable_for_memorydlg(hDlg);
    break;

    case WM_COMMAND:
	if (recursive > 0)
	    break;
	recursive++;
	values_to_memorydlg (hDlg);
	recursive--;
	break;

    case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;

	case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
    }
    return FALSE;
}

static void values_to_kickstartdlg (HWND hDlg)
{
    SetDlgItemText (hDlg, IDC_ROMFILE, workprefs.romfile);
    SetDlgItemText (hDlg, IDC_KEYFILE, workprefs.keyfile);
}

static BOOL CALLBACK KickstartDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
     case WM_INITDIALOG:
	pages[KICKSTART_ID] = hDlg;

     case WM_USER:
	values_to_kickstartdlg (hDlg);
	return TRUE;

    case WM_COMMAND:
	switch (wParam) {
	 case IDC_KICKCHOOSER:
	    DiskSelection( hDlg, IDC_ROMFILE, 6, &workprefs );
	    break;
	 case IDC_KEYCHOOSER:
	    DiskSelection( hDlg, IDC_KEYFILE, 7, &workprefs );
        break;
	default:
        if( SendMessage( GetDlgItem( hDlg, IDC_ROMFILE ), EM_GETMODIFY, 0, 0 ) )
        {
	        GetDlgItemText( hDlg, IDC_ROMFILE, workprefs.romfile, CFG_ROM_LENGTH);
            SendMessage( GetDlgItem( hDlg, IDC_ROMFILE ), EM_SETMODIFY, 0, 0 );
        }
        if( SendMessage( GetDlgItem( hDlg, IDC_KEYFILE ), EM_GETMODIFY, 0, 0 ) )
        {
	        GetDlgItemText( hDlg, IDC_KEYFILE, workprefs.keyfile, CFG_KEY_LENGTH);
            SendMessage( GetDlgItem( hDlg, IDC_ROMFILE ), EM_SETMODIFY, 0, 0 );
        }
	}
	break;

    case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;
	 case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
    }
    return FALSE;
}

static void enable_for_miscdlg (HWND hDlg)
{
    if( !full_property_sheet )
    {
        EnableWindow( GetDlgItem( hDlg, IDC_JULIAN), FALSE);
        EnableWindow( GetDlgItem( hDlg, IDC_SOCKETS), FALSE);
        EnableWindow( GetDlgItem( hDlg, IDC_SHOWGUI ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_AUTOCONFIG ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_ILLEGAL ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CREATELOGFILE ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_NOSPEED ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_NOSOUND ), FALSE );
        ShowWindow( GetDlgItem( hDlg, IDC_RESETAMIGA ), SW_SHOW );
        ShowWindow( GetDlgItem( hDlg, IDC_QUITEMU ), SW_SHOW );
    }
}

static void values_to_miscdlg (HWND hDlg)
{
    CheckDlgButton( hDlg, IDC_BLITIMM, workprefs.immediate_blits);
    CheckDlgButton( hDlg, IDC_BLIT32, workprefs.blits_32bit_enabled);
    CheckDlgButton( hDlg, IDC_SOCKETS, workprefs.socket_emu );
    CheckDlgButton( hDlg, IDC_ILLEGAL, workprefs.illegal_mem);
    CheckDlgButton( hDlg, IDC_SHOWGUI, workprefs.start_gui);
    CheckDlgButton( hDlg, IDC_AUTOCONFIG, workprefs.automount_uaedev);
    CheckDlgButton( hDlg, IDC_JULIAN, workprefs.win32_middle_mouse );
    CheckDlgButton( hDlg, IDC_CREATELOGFILE, workprefs.win32_logfile );
    CheckDlgButton( hDlg, IDC_SHOWLEDS, workprefs.leds_on_screen );
    CheckDlgButton( hDlg, IDC_NOSPEED, workprefs.win32_iconified_nospeed );
    CheckDlgButton( hDlg, IDC_NOSOUND, workprefs.win32_iconified_nosound );
}

static BOOL CALLBACK MiscDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
     case WM_INITDIALOG:
	pages[MISC_ID] = hDlg;

     case WM_USER:
	values_to_miscdlg (hDlg);
	enable_for_miscdlg (hDlg);
	return TRUE;

     case WM_COMMAND:
    switch( wParam )
    {
    case IDC_BLITIMM:
    	workprefs.immediate_blits = IsDlgButtonChecked (hDlg, IDC_BLITIMM);
        break;
    case IDC_BLIT32:
    	workprefs.blits_32bit_enabled = IsDlgButtonChecked (hDlg, IDC_BLIT32);
        break;
    case IDC_RESETAMIGA:
        uae_reset();
        break;
    case IDC_QUITEMU:
        uae_quit();
        PropSheet_PressButton( hPropertySheet, PSBTN_CANCEL );
        break;
    case IDC_JULIAN:
    	workprefs.win32_middle_mouse = IsDlgButtonChecked( hDlg, IDC_JULIAN );
        break;
    case IDC_SOCKETS:
        workprefs.socket_emu   = IsDlgButtonChecked( hDlg, IDC_SOCKETS );
        break;
     case IDC_ILLEGAL:
         workprefs.illegal_mem = IsDlgButtonChecked (hDlg, IDC_ILLEGAL);
         break;
     case IDC_AUTOCONFIG:
         workprefs.automount_uaedev = IsDlgButtonChecked (hDlg, IDC_AUTOCONFIG);
         break;
     case IDC_SHOWGUI:
         workprefs.start_gui = IsDlgButtonChecked (hDlg, IDC_SHOWGUI);
         break;
     case IDC_CREATELOGFILE:
         workprefs.win32_logfile = IsDlgButtonChecked( hDlg, IDC_CREATELOGFILE );
         break;
     case IDC_SHOWLEDS:
         workprefs.leds_on_screen = IsDlgButtonChecked( hDlg, IDC_SHOWLEDS );
         break;
     case IDC_NOSPEED:
         workprefs.win32_iconified_nospeed = IsDlgButtonChecked( hDlg, IDC_NOSPEED );
         break;
     case IDC_NOSOUND:
         workprefs.win32_iconified_nosound = IsDlgButtonChecked( hDlg, IDC_NOSOUND );
         break;
    }
	break;

     case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;

	 case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
    }
    return FALSE;
}

static int cpu_ids[] = { IDC_CPU0, IDC_CPU0, IDC_CPU1, IDC_CPU1, IDC_CPU2, IDC_CPU4, IDC_CPU3, IDC_CPU5 };

static void enable_for_cpudlg (HWND hDlg)
{
    /* NOTE: The ONLY way we get a CPU panel in the GUI once running is if the CPU type is set for
             adjustable mode. */
    if( !full_property_sheet )
    {
        EnableWindow( GetDlgItem( hDlg, IDC_CPU0 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CPU1 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CPU2 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CPU3 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CPU4 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CPU5 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CS_HOST ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_CS_68000 ), FALSE );
        EnableWindow( GetDlgItem( hDlg, IDC_COMPATIBLE ), FALSE );

        EnableWindow (GetDlgItem (hDlg, IDC_SPEED), TRUE );
        EnableWindow (GetDlgItem (hDlg, IDC_CS_CPU_TEXT), TRUE );
        EnableWindow (GetDlgItem (hDlg, IDC_CS_CHIPSET_TEXT), TRUE );
        EnableWindow (GetDlgItem (hDlg, IDC_CPUTEXT), TRUE );
    }
    else
    {
        /* These four items only get enabled when adjustable CPU style is enabled */
        EnableWindow (GetDlgItem (hDlg, IDC_SPEED), workprefs.m68k_speed > 0);
        EnableWindow (GetDlgItem (hDlg, IDC_CS_CPU_TEXT), workprefs.m68k_speed > 0);
        EnableWindow (GetDlgItem (hDlg, IDC_CS_CHIPSET_TEXT), workprefs.m68k_speed > 0);
        EnableWindow (GetDlgItem (hDlg, IDC_CPUTEXT), workprefs.m68k_speed > 0 );

        /* The "compatible" checkbox is only available when CPU type is 68000 */
        EnableWindow (GetDlgItem (hDlg, IDC_COMPATIBLE), workprefs.cpu_level == 0);
    }
}

static void values_to_cpudlg (HWND hDlg)
{
    SendDlgItemMessage (hDlg, IDC_SPEED, TBM_SETPOS, TRUE, workprefs.m68k_speed <= 0 ? 1 : workprefs.m68k_speed);
    SetDlgItemInt( hDlg, IDC_CPUTEXT, workprefs.m68k_speed <= 0 ? 1 : workprefs.m68k_speed, FALSE );
    CheckDlgButton (hDlg, IDC_COMPATIBLE, workprefs.cpu_compatible);
    CheckRadioButton (hDlg, IDC_CPU0, IDC_CPU5, cpu_ids[workprefs.cpu_level * 2 + !workprefs.address_space_24]);

    if (workprefs.m68k_speed == -1)
	CheckRadioButton (hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_HOST);
    else if (workprefs.m68k_speed == 0)
	CheckRadioButton (hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_68000);
    else
	CheckRadioButton (hDlg, IDC_CS_HOST, IDC_CS_ADJUSTABLE, IDC_CS_ADJUSTABLE);
}

static void values_from_cpudlg (HWND hDlg)
{
    int newcpu;

    workprefs.cpu_compatible = IsDlgButtonChecked (hDlg, IDC_COMPATIBLE);
    workprefs.m68k_speed = (IsDlgButtonChecked (hDlg, IDC_CS_HOST) ? -1
			    : IsDlgButtonChecked (hDlg, IDC_CS_68000) ? 0
			    : SendMessage (GetDlgItem (hDlg, IDC_SPEED), TBM_GETPOS, 0, 0));

    newcpu = (IsDlgButtonChecked (hDlg, IDC_CPU0) ? 0
	      : IsDlgButtonChecked (hDlg, IDC_CPU1) ? 1
	      : IsDlgButtonChecked (hDlg, IDC_CPU2) ? 2
          : IsDlgButtonChecked (hDlg, IDC_CPU3) ? 3
          : IsDlgButtonChecked (hDlg, IDC_CPU4) ? 4 : 5);
	/* When switching away from 68000, disable 24 bit addressing.  */
	switch( newcpu )
    {
    case 0:
    case 1:
    case 2:
    case 3:
	    workprefs.address_space_24 = 1;
        workprefs.cpu_level = newcpu;
        break;
    case 4:
    case 5:
        workprefs.address_space_24 = 0;
        workprefs.cpu_level = newcpu - 2;
        break;
    }
	if (newcpu > 0)
	    workprefs.cpu_compatible = 0;
    if( pages[ KICKSTART_ID ] )
	    SendMessage( pages[ KICKSTART_ID ], WM_USER, 0, 0 );
    if( pages[ DISPLAY_ID ] )
	    SendMessage( pages[ DISPLAY_ID ], WM_USER, 0, 0 );
    if( pages[ MEMORY_ID ] )
        SendMessage( pages[ MEMORY_ID ], WM_USER, 0, 0 );
}

static BOOL CALLBACK CPUDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    char buffer[3];
    static int recursive = 0;

    switch (msg) {
     case WM_INITDIALOG:
	pages[CPU_ID] = hDlg;
	SendDlgItemMessage (hDlg, IDC_SPEED, TBM_SETRANGE, TRUE, MAKELONG (MIN_M68K_PRIORITY, MAX_M68K_PRIORITY));
	SendDlgItemMessage (hDlg, IDC_SPEED, TBM_SETPAGESIZE, 0, 1);

     case WM_USER:
	recursive++;
	values_to_cpudlg (hDlg);
	enable_for_cpudlg (hDlg);
	recursive--;
	return TRUE;

     case WM_COMMAND:
	if (recursive > 0)
	    break;
	recursive++;
	values_from_cpudlg (hDlg);
	values_to_cpudlg (hDlg);
	enable_for_cpudlg (hDlg);
	recursive--;
	break;

    case WM_HSCROLL:
	workprefs.m68k_speed = SendMessage( GetDlgItem( hDlg, IDC_SPEED ), TBM_GETPOS, 0, 0 );
    sprintf( buffer, "%d", workprefs.m68k_speed <= 0 ? 1 : workprefs.m68k_speed );
    SetDlgItemText( hDlg, IDC_CPUTEXT, buffer );
    break;

     case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;

	 case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
    }
    return FALSE;
}

static void enable_for_sounddlg (HWND hDlg)
{
    EnableWindow (GetDlgItem (hDlg, IDC_FREQUENCY), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_11KHZ), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_22KHZ), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_44KHZ), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_48KHZ), workprefs.produce_sound > 0);

    EnableWindow (GetDlgItem (hDlg, IDC_SOUNDSIZE), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_8BIT), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_16BIT), workprefs.produce_sound > 0);

    EnableWindow (GetDlgItem (hDlg, IDC_STEREO), workprefs.produce_sound > 0);

    EnableWindow (GetDlgItem (hDlg, IDC_SOUNDSTYLE), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_SOUNDSTYLE0), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_SOUNDSTYLE1), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_SOUNDSTYLE2), workprefs.produce_sound > 0);
    EnableWindow (GetDlgItem (hDlg, IDC_SOUNDSTYLE3), workprefs.produce_sound > 0);
}

static void values_to_sounddlg (HWND hDlg)
{
    int which_button;

    if (workprefs.sound_freq <= 11025)
	which_button = IDC_11KHZ;
    else if (workprefs.sound_freq <= 22050)
	which_button = IDC_22KHZ;
    else if (workprefs.sound_freq <= 44100)
	which_button = IDC_44KHZ;
    else
	which_button = IDC_48KHZ;
    CheckRadioButton (hDlg, IDC_11KHZ, IDC_48KHZ, which_button);

    CheckRadioButton (hDlg, IDC_8BIT, IDC_16BIT, workprefs.sound_bits == 16 ? IDC_16BIT : IDC_8BIT);

    switch (workprefs.produce_sound) {
     case 0: which_button = IDC_SOUND0; break;
     case 1: which_button = IDC_SOUND1; break;
     case 2: which_button = IDC_SOUND2; break;
     case 3: which_button = IDC_SOUND3; break;
    }
    
    CheckRadioButton( hDlg, IDC_SOUND0, IDC_SOUND3, which_button );
    switch( workprefs.win32_sound_style )
    {
    case 0:
        which_button = IDC_SOUNDSTYLE0;
        break;
    case 1:
        which_button = IDC_SOUNDSTYLE1;
        break;
    case 2:
        which_button = IDC_SOUNDSTYLE2;
        break;
    case 3:
        which_button = IDC_SOUNDSTYLE3;
        break;
    }
    CheckRadioButton( hDlg, IDC_SOUNDSTYLE0, IDC_SOUNDSTYLE3, which_button );

    CheckDlgButton( hDlg, IDC_STEREO, workprefs.stereo );
}

static void values_from_sounddlg (HWND hDlg)
{
    workprefs.sound_bits = IsDlgButtonChecked (hDlg, IDC_8BIT) ? 8 : 16;
    workprefs.sound_freq = (IsDlgButtonChecked (hDlg, IDC_11KHZ) ? 11025
			    : IsDlgButtonChecked (hDlg, IDC_22KHZ) ? 22050
			    : IsDlgButtonChecked (hDlg, IDC_44KHZ) ? 44100 : 48000);
    workprefs.produce_sound = (IsDlgButtonChecked (hDlg, IDC_SOUND0) ? 0
			       : IsDlgButtonChecked (hDlg, IDC_SOUND1) ? 1
			       : IsDlgButtonChecked (hDlg, IDC_SOUND2) ? 2 : 3);
    workprefs.stereo = IsDlgButtonChecked (hDlg, IDC_STEREO) ? 1 : 0;
    workprefs.win32_sound_style = (IsDlgButtonChecked (hDlg, IDC_SOUNDSTYLE0) ? 0
        : IsDlgButtonChecked( hDlg, IDC_SOUNDSTYLE1 ) ? 1
        : IsDlgButtonChecked( hDlg, IDC_SOUNDSTYLE2 ) ? 2 : 3);
}

static BOOL CALLBACK SoundDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;
    switch (msg) {
     case WM_INITDIALOG:
	pages[SOUND_ID] = hDlg;

     case WM_USER:
	recursive++;
	values_to_sounddlg (hDlg);
	enable_for_sounddlg (hDlg);
	recursive--;
	return TRUE;

     case WM_COMMAND:
	if (recursive > 0)
	    break;
	recursive++;
	values_from_sounddlg (hDlg);
	enable_for_sounddlg (hDlg);
	recursive--;
	break;

     case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;
	 case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
	break;
    }
    return FALSE;
}

struct fsvdlg_vals
{
    char volume[4096];
    char rootdir[4096];
    int rw;
};

static struct fsvdlg_vals empty_fsvdlg = { "", "", 1 };
static struct fsvdlg_vals current_fsvdlg;

struct hfdlg_vals
{
    char volumename[4096];
    char filename[4096];
    int sectors;
    int reserved;
    int surfaces;
    int cylinders;
    int blocksize;
    int rw;
};

static struct hfdlg_vals empty_hfdlg = { "", "", 32, 2, 1, 0, 512, 1 };
static struct hfdlg_vals current_hfdlg;

static int CALLBACK VolumeSettingsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;
    BROWSEINFO browse_info;
    char directory_path[MAX_PATH] = "";
    LPITEMIDLIST browse;

    browse_info.hwndOwner = hDlg;
    browse_info.pidlRoot = NULL;
    browse_info.pszDisplayName = directory_path;
    browse_info.lpszTitle = "Please select your file-system root directory...";
    browse_info.ulFlags = BIF_DONTGOBELOWDOMAIN | BIF_RETURNONLYFSDIRS;
    browse_info.lpfn = NULL;
    browse_info.iImage = 0;

    switch (msg) {
     case WM_INITDIALOG:
	recursive++;
	SetDlgItemText (hDlg, IDC_VOLUME_NAME, current_fsvdlg.volume);
	SetDlgItemText (hDlg, IDC_PATH_NAME, current_fsvdlg.rootdir);
	CheckDlgButton (hDlg, IDC_RW, current_fsvdlg.rw);
	recursive--;
	return TRUE;

     case WM_COMMAND:
	if (recursive)
	    break;
	recursive++;
	if (HIWORD (wParam) == BN_CLICKED) {
	    switch (LOWORD (wParam)) {
	     case IDC_SELECTOR:
		if ((browse = SHBrowseForFolder (&browse_info)) != NULL) {
		    SHGetPathFromIDList (browse, directory_path);
		    SetDlgItemText (hDlg, IDC_PATH_NAME, directory_path);
		}
		break;
	     case IDOK:
		if (strlen (current_fsvdlg.rootdir) == 0) {
		    MessageBox (hDlg, "You must select a path!", "Settings Error",
				MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
		    break;
		}
		if (strlen (current_fsvdlg.volume) == 0) {
		    MessageBox (hDlg, "You must select a name for the volume!", "Settings Error",
				MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
		    break;
		}
		EndDialog (hDlg, 1);

		break;
	     case IDCANCEL:
		EndDialog (hDlg, 0);
		break;
	    }
	}
	GetDlgItemText (hDlg, IDC_PATH_NAME, current_fsvdlg.rootdir, sizeof current_fsvdlg.rootdir);
	GetDlgItemText (hDlg, IDC_VOLUME_NAME, current_fsvdlg.volume, sizeof current_fsvdlg.volume);
	current_fsvdlg.rw = IsDlgButtonChecked (hDlg, IDC_RW);
	recursive--;
	break;
    }
    return FALSE;
}

static int CALLBACK HardfileSettingsProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;
    UINT setting;

    switch (msg) {
     case WM_INITDIALOG:
	recursive++;
	SetDlgItemText (hDlg, IDC_PATH_NAME, current_hfdlg.filename);
	SetDlgItemInt( hDlg, IDC_SECTORS, current_hfdlg.sectors, FALSE);
	SetDlgItemInt( hDlg, IDC_HEADS, current_hfdlg.surfaces, FALSE);
	SetDlgItemInt( hDlg, IDC_RESERVED, current_hfdlg.reserved, FALSE);
    SetDlgItemInt( hDlg, IDC_BLOCKSIZE, current_hfdlg.blocksize, FALSE);
	CheckDlgButton (hDlg, IDC_RW, current_hfdlg.rw);
	recursive--;
	return TRUE;

     case WM_COMMAND:
	if (recursive)
	    break;
	recursive++;

	if (HIWORD (wParam) == BN_CLICKED) {
	    switch (LOWORD (wParam)) {
	     case IDC_CREATEHF:
		setting = CalculateHardfileSize (hDlg);
		if( !CreateHardFile(hDlg, setting) )
        {
		    MessageBox( hDlg, "Failed to create hard-file...", "Creation Error",
				MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
        }
		break;
	     case IDC_SELECTOR:
		DiskSelection (hDlg, IDC_PATH_NAME, 2, &workprefs );
		break;
	     case IDOK:
		if (strlen (current_hfdlg.filename) == 0) {
		    MessageBox (hDlg, "You must select a file...", "Settings Error",
				MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
		    break;
		}
		EndDialog (hDlg, 1);
		break;
	     case IDCANCEL:
		EndDialog (hDlg, 0);
		break;
	    }
	}

	GetDlgItemText (hDlg, IDC_PATH_NAME, current_hfdlg.filename, sizeof current_hfdlg.filename);
	current_hfdlg.sectors   = GetDlgItemInt( hDlg, IDC_SECTORS, FALSE, FALSE );
	current_hfdlg.reserved  = GetDlgItemInt( hDlg, IDC_RESERVED, FALSE, FALSE );
	current_hfdlg.surfaces  = GetDlgItemInt( hDlg, IDC_HEADS, FALSE, FALSE );
    current_hfdlg.blocksize = GetDlgItemInt( hDlg, IDC_BLOCKSIZE, FALSE, FALSE );
	current_hfdlg.rw = IsDlgButtonChecked (hDlg, IDC_RW);
	recursive--;

	break;
    }
    return FALSE;
}

static void new_filesys (HWND hDlg)
{
    const char *result;

    result = add_filesys_unit (workprefs.mountinfo, current_fsvdlg.volume,
			       current_fsvdlg.rootdir, ! current_fsvdlg.rw, 0, 0, 0, 0, 0);
    if (result)
	MessageBox (hDlg, result, "Bad directory",
		    MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
}

static void new_hardfile (HWND hDlg)
{
    const char *result;

    result = add_filesys_unit (workprefs.mountinfo, 0, current_hfdlg.filename,
			       ! current_hfdlg.rw, current_hfdlg.sectors, current_hfdlg.surfaces,
                   current_hfdlg.reserved, current_hfdlg.blocksize, 0);
    if (result)
	MessageBox (hDlg, result, "Bad hardfile",
		    MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
}

static void harddisk_remove (HWND hDlg)
{
    int entry = listview_find_selected (GetDlgItem (hDlg, IDC_VOLUMELIST));
    if (entry < 0)
	return;
    kill_filesys_unit (workprefs.mountinfo, entry);
}

static void harddisk_move (HWND hDlg, int up)
{
    int entry = listview_find_selected (GetDlgItem (hDlg, IDC_VOLUMELIST));
    if (entry < 0)
	return;
    move_filesys_unit (workprefs.mountinfo, entry, up ? entry - 1 : entry + 1);
}

static void harddisk_edit (HWND hDlg)
{
    char *volume, *rootdir;
    int size, readonly;

    int entry = listview_find_selected (GetDlgItem (hDlg, IDC_VOLUMELIST));
    if (entry < 0)
	return;

    get_filesys_unit (workprefs.mountinfo, entry, &volume, &rootdir, &readonly,
		      &current_hfdlg.sectors, &current_hfdlg.surfaces, &current_hfdlg.reserved,
              &current_hfdlg.blocksize, &current_hfdlg.cylinders, &size);

    if (volume == 0) 
    {
	    /* Hardfile */
	    strncpy (current_hfdlg.filename, rootdir, (sizeof current_hfdlg.filename) - 1);
	    current_hfdlg.filename[(sizeof current_hfdlg.filename) - 1] = '\0';
	    current_hfdlg.rw = !readonly;
	    if (DialogBox (hInst, MAKEINTRESOURCE (IDD_HARDFILE), hDlg, HardfileSettingsProc)) 
        {
	        const char *result;
	        result    = set_filesys_unit (workprefs.mountinfo, entry, 0, current_hfdlg.filename,
				           ! current_hfdlg.rw, current_hfdlg.sectors, current_hfdlg.surfaces,
                           current_hfdlg.reserved, current_hfdlg.blocksize, 0);
	        if (result)
		    MessageBox (hDlg, result, "Bad hardfile",
			        MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
	    }
    }
    else
    {
	    /* Filesystem */
	    strncpy (current_fsvdlg.rootdir, rootdir, (sizeof current_fsvdlg.rootdir) - 1);
	    current_fsvdlg.rootdir[(sizeof current_fsvdlg.rootdir) - 1] = '\0';
	    strncpy (current_fsvdlg.volume, volume, (sizeof current_fsvdlg.volume) - 1);
	    current_fsvdlg.volume[(sizeof current_fsvdlg.volume) - 1] = '\0';
	    current_fsvdlg.rw = !readonly;
	    if (DialogBox (hInst, MAKEINTRESOURCE (IDD_FILESYS), hDlg, VolumeSettingsProc)) {
	        const char *result;
	        result = set_filesys_unit (workprefs.mountinfo, entry, current_fsvdlg.volume,
				           current_fsvdlg.rootdir, ! current_fsvdlg.rw, 0, 0, 0, 0, 0);
	        if (result)
		    MessageBox (hDlg, result, "Bad hardfile",
			        MB_OK | MB_ICONERROR | MB_APPLMODAL | MB_SETFOREGROUND);
	    }
    }
    free (volume);
    free (rootdir);
}

static void harddiskdlg_button (HWND hDlg, int button)
{
    switch (button) {
     case IDC_NEW_FS:
	current_fsvdlg = empty_fsvdlg;
	if (DialogBox (hInst, MAKEINTRESOURCE (IDD_FILESYS), hDlg, VolumeSettingsProc))
	    new_filesys (hDlg);
	break;

     case IDC_NEW_HF:
	current_hfdlg = empty_hfdlg;
	if (DialogBox (hInst, MAKEINTRESOURCE (IDD_HARDFILE), hDlg, HardfileSettingsProc))
	    new_hardfile (hDlg);
	break;

     case IDC_EDIT:
	harddisk_edit (hDlg);
	break;

     case IDC_REMOVE:
	harddisk_remove (hDlg);
	break;

     case IDC_UP:
	harddisk_move (hDlg, 1);
	break;

     case IDC_DOWN:
	harddisk_move (hDlg, 0);
	break;
     
    case IDC_MAPDRIVES:
        workprefs.automount_drives = IsDlgButtonChecked( hDlg, button );
        break;
    }
}

static void harddiskdlg_volume_notify (HWND hDlg, NM_LISTVIEW *nmlistview)
{
    HWND list = nmlistview->hdr.hwndFrom;
    int dblclick = 0;
    int entry = 0;

    switch (nmlistview->hdr.code) {
     case NM_DBLCLK:
	dblclick = 1;
	/* fall through */
     case NM_CLICK:
	entry = listview_entry_from_click (list);
	if (entry >= 0 && dblclick) {
	    harddisk_edit (hDlg);
        InitializeListView( hDlg );
	}
	break;
    }
}

static BOOL CALLBACK HarddiskDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg) {
     case WM_INITDIALOG:
	pages[HARDDISK_ID] = hDlg;

    case WM_USER:
        CheckDlgButton( hDlg, IDC_MAPDRIVES, workprefs.automount_drives );
        InitializeListView( hDlg );
	break;

     case WM_COMMAND:
	if (HIWORD (wParam) == BN_CLICKED)
    {
	    harddiskdlg_button (hDlg, LOWORD (wParam));
        InitializeListView( hDlg );
    }
	break;

     case WM_NOTIFY:
	if (((LPNMHDR) lParam)->idFrom == IDC_VOLUMELIST)
	    harddiskdlg_volume_notify (hDlg, (NM_LISTVIEW *) lParam);
	else {
	    switch (((NMHDR *) lParam)->code) {
	     case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
             transfer_prefs(0);
		break;
	     case PSN_RESET:
		if (allow_quit) {
		    quit_program = 1;
		    regs.spcflags |= SPCFLAG_BRK;
		}
		break;
	    }
	}
	return TRUE;
     default:
	return FALSE;
    }

    return FALSE;
}

static BOOL CALLBACK FloppyDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;

    switch (msg) {
     case WM_INITDIALOG:
	pages[FLOPPY_ID] = hDlg;
    ShowWindow( GetDlgItem( hDlg, IDC_DISABLE1 ), SW_HIDE );
    ShowWindow( GetDlgItem( hDlg, IDC_DISABLE2 ), SW_HIDE );
    ShowWindow( GetDlgItem( hDlg, IDC_DISABLE3 ), SW_HIDE );

     case WM_USER:
	recursive++;
	SetDlgItemText (hDlg, IDC_DF0TEXT, workprefs.df[0]);
	SetDlgItemText (hDlg, IDC_DF1TEXT, workprefs.df[1]);
	SetDlgItemText (hDlg, IDC_DF2TEXT, workprefs.df[2]);
	SetDlgItemText (hDlg, IDC_DF3TEXT, workprefs.df[3]);
	recursive--;
	break;

     case WM_COMMAND:
	if (recursive > 0)
	    break;
	recursive++;
	switch (wParam) {
	 case IDC_DF0:
	    DiskSelection (hDlg, wParam, 0, &workprefs );
	    break;
	 case IDC_DF1:
	    DiskSelection (hDlg, wParam, 0, &workprefs );
        break;
	 case IDC_DF2:
	    DiskSelection (hDlg, wParam, 0, &workprefs );
        break;
	 case IDC_DF3:
	    DiskSelection (hDlg, wParam, 0, &workprefs );
        break;
	 case IDC_EJECT0:
        disk_eject(0);
        SetDlgItemText (hDlg, IDC_DF0TEXT, "");
        workprefs.df[0][0] = 0;
	    break;
	 case IDC_EJECT1:
        disk_eject(1);
	    SetDlgItemText (hDlg, IDC_DF1TEXT, "");
        workprefs.df[1][0] = 0;
	    break;
	 case IDC_EJECT2:
        disk_eject(2);
	    SetDlgItemText (hDlg, IDC_DF2TEXT, "");
        workprefs.df[2][0] = 0;
        break;
	 case IDC_EJECT3:
        disk_eject(3);
	    SetDlgItemText (hDlg, IDC_DF3TEXT, "");
        workprefs.df[3][0] = 0;
        break;
	 case IDC_CREATE:
	    DiskSelection (hDlg, wParam, 1, &workprefs );
	    break;
	}
    if( SendMessage( GetDlgItem( hDlg, IDC_DF0TEXT ), EM_GETMODIFY, 0, 0 ) )
    {
    	GetDlgItemText (hDlg, IDC_DF0TEXT, workprefs.df[0], 255);
        SendMessage( GetDlgItem( hDlg, IDC_DF0TEXT ), EM_SETMODIFY, 0, 0 );
    }

    if( SendMessage( GetDlgItem( hDlg, IDC_DF1TEXT ), EM_GETMODIFY, 0, 0 ) )
    {
    	GetDlgItemText (hDlg, IDC_DF1TEXT, workprefs.df[1], 255);
        SendMessage( GetDlgItem( hDlg, IDC_DF1TEXT ), EM_SETMODIFY, 0, 0 );
    }

    if( SendMessage( GetDlgItem( hDlg, IDC_DF2TEXT ), EM_GETMODIFY, 0, 0 ) )
    {
    	GetDlgItemText (hDlg, IDC_DF2TEXT, workprefs.df[2], 255);
        SendMessage( GetDlgItem( hDlg, IDC_DF2TEXT ), EM_SETMODIFY, 0, 0 );
    }

    if( SendMessage( GetDlgItem( hDlg, IDC_DF3TEXT ), EM_GETMODIFY, 0, 0 ) )
    {
    	GetDlgItemText (hDlg, IDC_DF3TEXT, workprefs.df[3], 255);
        SendMessage( GetDlgItem( hDlg, IDC_DF3TEXT ), EM_SETMODIFY, 0, 0 );
    }
	recursive--;
	break;

     case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
         transfer_prefs(0);
	    break;
	 case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
	return TRUE;
     default:
	return FALSE;
    }

    return FALSE;
}

static int joy0idc[] = {
    IDC_PORT0_JOY0, IDC_PORT0_JOY1, IDC_PORT0_MOUSE, IDC_PORT0_KBDA, IDC_PORT0_KBDB, IDC_PORT0_KBDC
};

static int joy1idc[] = {
    IDC_PORT1_JOY0, IDC_PORT1_JOY1, IDC_PORT1_MOUSE, IDC_PORT1_KBDA, IDC_PORT1_KBDB, IDC_PORT1_KBDC
};

static void enable_for_portsdlg( HWND hDlg )
{
    int i;
    if (! full_property_sheet) 
    {
	    /* Disable certain controls which are only to be set once at start-up... */
	    EnableWindow (GetDlgItem (hDlg, IDC_SERIAL), FALSE);
	    EnableWindow (GetDlgItem (hDlg, IDC_PARALLEL), FALSE);
    }
    for( i = 0; i < 6; i++ )
    {
        EnableWindow( GetDlgItem( hDlg, joy0idc[i] ), TRUE );
        EnableWindow( GetDlgItem( hDlg, joy1idc[i] ), TRUE );
    }
}

static void UpdatePortRadioButtons( HWND hDlg )
{
    int which_button1, which_button2;

    enable_for_portsdlg( hDlg );
	which_button1 = joy0idc[workprefs.jport0];
	if (CheckRadioButton (hDlg, IDC_PORT0_JOY0, IDC_PORT0_KBDC, which_button1) == 0)
	    which_button1 = 0;
    else
    {
        EnableWindow( GetDlgItem( hDlg, joy1idc[workprefs.jport0] ), FALSE );
    }
	which_button2 = joy1idc[workprefs.jport1];
    if( workprefs.jport1 == workprefs.jport0 )
    {
        if( which_button2 == IDC_PORT1_KBDC )
            which_button2 = IDC_PORT1_KBDB;
        else
            which_button2++;
    }
	if (CheckRadioButton (hDlg, IDC_PORT1_JOY0, IDC_PORT1_KBDC, which_button2) == 0)
	    which_button2 = 0;
    else
    {
        EnableWindow( GetDlgItem( hDlg, joy0idc[ workprefs.jport1 ] ), FALSE );
    }
}

static void values_from_portsdlg (HWND hDlg)
{
    int item;
    /* 0 - joystick 0
     * 1 - joystick 1
     * 2 - mouse
     * 3 - numpad
     * 4 - cursor keys
     * 5 - elsewhere
     */
    if (IsDlgButtonChecked (hDlg, IDC_PORT0_JOY0)) {
	    workprefs.jport0 = 0;
    }
    if (IsDlgButtonChecked (hDlg, IDC_PORT0_JOY1)) {
	    workprefs.jport0 = 1;
    }
    if (IsDlgButtonChecked (hDlg, IDC_PORT0_MOUSE))
	    workprefs.jport0 = 2;
    if (IsDlgButtonChecked (hDlg, IDC_PORT0_KBDA))
	    workprefs.jport0 = 3;
    if (IsDlgButtonChecked (hDlg, IDC_PORT0_KBDB))
	    workprefs.jport0 = 4;
    if (IsDlgButtonChecked (hDlg, IDC_PORT0_KBDC))
	    workprefs.jport0 = 5;

    if (IsDlgButtonChecked (hDlg, IDC_PORT1_JOY0)) {
	    workprefs.jport1 = 0;
    }
    if (IsDlgButtonChecked (hDlg, IDC_PORT1_JOY1)) {
	    workprefs.jport1 = 1;
    }
    if (IsDlgButtonChecked (hDlg, IDC_PORT1_MOUSE))
	    workprefs.jport1 = 2;
    if (IsDlgButtonChecked (hDlg, IDC_PORT1_KBDA))
	    workprefs.jport1 = 3;
    if (IsDlgButtonChecked (hDlg, IDC_PORT1_KBDB))
	    workprefs.jport1 = 4;
    if (IsDlgButtonChecked (hDlg, IDC_PORT1_KBDC))
	    workprefs.jport1 = 5;

    GetDlgItemText (hDlg, IDC_PARALLEL, workprefs.prtname, CFG_PAR_LENGTH);

    item = SendDlgItemMessage (hDlg, IDC_SERIAL, CB_GETCURSEL, 0, 0L);
    switch (item) {
     case 1:
     case 2:
     case 3:
     case 4:
	workprefs.use_serial = 1;
	sprintf (workprefs.sername, "COM%d", item);
	break;
     default:
	workprefs.use_serial = 0;
    strcpy( workprefs.sername, "" );
	break;
    }
}

static void values_to_portsdlg (HWND hDlg)
{
    LONG item_height;
    RECT rect;

    SetDlgItemText (hDlg, IDC_PARALLEL, workprefs.prtname);
    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_RESETCONTENT, 0, 0L);
    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM) "None");
    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM) "COM1");
    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM) "COM2");
    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM) "COM3");
    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_ADDSTRING, 0, (LPARAM) "COM4");
    if( strcasecmp( workprefs.sername, "none" ) == 0 ) 
    {
	    SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, 0, 0L);
        workprefs.use_serial = 0;
    }
    else
    {
        workprefs.use_serial = 1;
	    switch (workprefs.sername[3]) 
        {
	     case '2':
	        SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, 2, 0L);
	        break;
	     case '3':
	        SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, 3, 0L);
	        break;
	     case '4':
	        SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, 4, 0L);
	        break;
	     default:
	        SendDlgItemMessage (hDlg, IDC_SERIAL, CB_SETCURSEL, 1, 0L);
	        break;
	    }
    }

    /* Retrieve the height, in pixels, of a list item. */
    item_height = SendDlgItemMessage (hDlg, IDC_SERIAL, CB_GETITEMHEIGHT, 0, 0L);
    if (item_height != CB_ERR) {
	/* Get actual box position and size. */
	GetWindowRect (GetDlgItem (hDlg, IDC_SERIAL), &rect);
	rect.bottom = (rect.top + item_height * 5
		       + SendDlgItemMessage (hDlg, IDC_SERIAL, CB_GETITEMHEIGHT, (WPARAM) - 1, 0L)
		       + item_height);
	SetWindowPos (GetDlgItem (hDlg, IDC_SERIAL), 0, 0, 0, rect.right - rect.left,
		      rect.bottom - rect.top, SWP_NOMOVE | SWP_NOZORDER);
    }
}

/* Handle messages for the Joystick Settings page of our property-sheet */
static BOOL CALLBACK PortsDlgProc (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    static int recursive = 0;
    int temp;

    switch (msg) {
     case WM_INITDIALOG:
	pages[PORTS_ID] = hDlg;

     case WM_USER:
	recursive++;
    enable_for_portsdlg( hDlg );
    values_to_portsdlg (hDlg);
	recursive--;
	return TRUE;

    case WM_COMMAND:
        if( wParam == IDC_SWAP )
        {
            temp = workprefs.jport0;
            workprefs.jport0 = workprefs.jport1;
            workprefs.jport1 = temp;
            UpdatePortRadioButtons( hDlg );
        }
        else
        {
	        if (recursive > 0)
	            break;
	        recursive++;
	        values_from_portsdlg (hDlg);
            UpdatePortRadioButtons( hDlg );
	        recursive--;
        }
	break;

     case WM_NOTIFY:
	switch (((NMHDR *) lParam)->code) {
	 case PSN_APPLY:
    /* Copy stuff from workprefs and config_xxx settings */
    transfer_prefs(0);
	    break;
	 case PSN_RESET:
	    if (allow_quit) {
		quit_program = 1;
		regs.spcflags |= SPCFLAG_BRK;
	    }
	    break;
	}
	return FALSE;
    }
    return FALSE;
}

static void CALLBACK InitPropertySheet (HWND hDlg, UINT msg, LPARAM lParam)
{
    int i;
    hPropertySheet = hDlg;

    switch (msg) 
    {
        case PSCB_INITIALIZED:
        if (! full_property_sheet) 
        {
	        PropSheet_RemovePage( hDlg, 0, NULL ); /* Remove LoadSave */
            PropSheet_RemovePage( hDlg, 0, NULL ); /* Remove RAM */
	        PropSheet_RemovePage( hDlg, 0, NULL ); /* Remove ROM */
            PropSheet_RemovePage( hDlg, 2, NULL ); /* Remove Sound */
            if( workprefs.m68k_speed > 0 )
            {
                PropSheet_RemovePage (hDlg, 3, NULL); /* Remove HD */
            }
            else
            {
                PropSheet_RemovePage( hDlg, 0, NULL ); /* Remove CPU */
                PropSheet_RemovePage (hDlg, 2, NULL); /* Remove HD */
            }
	    }
        else
        {
	        for (i = 0; i < C_PAGES; i++)
	            pages[i] = NULL;
        }
    	break;
    }
}


#ifdef __GNUC__
#define DUN1 DUMMYUNIONNAME ## .
#define DUN2 DUMMYUNIONNAME2 ## .
#define DUN3 DUMMYUNIONNAME3 ## .
#else
#define DUN1
#define DUN2
#define DUN3
#endif

static void init_page (PROPSHEETPAGE *ppage, int id, int tmpl, int icon, int title,
               BOOL (CALLBACK FAR *func) (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam))
{
    ppage[id].dwSize = sizeof (PROPSHEETPAGE);
    ppage[id].dwFlags = PSP_USETITLE | PSP_USEICONID | ((id != ABOUT_ID ) ? PSP_HASHELP : 0);
    ppage[id].hInstance = hInst;
    ppage[id].DUN1 pszTemplate = MAKEINTRESOURCE (tmpl);
    ppage[id].DUN2 pszIcon = MAKEINTRESOURCE (icon);
    ppage[id].pszTitle = MAKEINTRESOURCE (title);
    ppage[id].pfnDlgProc = func;
    ppage[id].lParam = 0;
    ppage[id].pfnCallback = NULL;
    ppage[id].pcRefParent = NULL;
}

int GetSettings (int all_options)
{
    int psresult;
    PROPSHEETPAGE ppage[C_PAGES];
    PROPSHEETHEADER pHeader;

    full_property_sheet = all_options;
    allow_quit = all_options;
    pguiprefs = all_options ? &currprefs : &changed_prefs;

    transfer_prefs(1);

    init_page (ppage, LOADSAVE_ID, IDD_LOADSAVE, IDI_LOADSAVE, IDS_LOADSAVE, LoadSaveDlgProc);
    init_page (ppage, MEMORY_ID, IDD_MEMORY, IDI_MEMORY, IDS_MEMORY, MemoryDlgProc);
    init_page (ppage, KICKSTART_ID, IDD_KICKSTART, IDI_MEMORY, IDS_KICKSTART, KickstartDlgProc);
    init_page (ppage, CPU_ID, IDD_CPU, IDI_CPU, IDS_CPU, CPUDlgProc);
    init_page (ppage, DISPLAY_ID, IDD_DISPLAY, IDI_DISPLAY, IDS_DISPLAY, DisplayDlgProc);
    init_page (ppage, SOUND_ID, IDD_SOUND, IDI_SOUND, IDS_SOUND, SoundDlgProc);
    init_page (ppage, FLOPPY_ID, IDD_FLOPPY, IDI_FLOPPY, IDS_FLOPPY, FloppyDlgProc);
    init_page (ppage, HARDDISK_ID, IDD_HARDDISK, IDI_HARDDISK, IDS_HARDDISK, HarddiskDlgProc);
    init_page (ppage, PORTS_ID, IDD_PORTS, IDI_PORTS, IDS_PORTS, PortsDlgProc);
    init_page (ppage, MISC_ID, IDD_MISC, IDI_MISC, IDS_MISC, MiscDlgProc);
    init_page (ppage, ABOUT_ID, IDD_ABOUT, IDI_ABOUT, IDS_ABOUT, AboutDlgProc);

    pHeader.dwSize = sizeof (PROPSHEETHEADER);
    pHeader.dwFlags = PSH_PROPSHEETPAGE | PSH_PROPTITLE | PSH_USEICONID | PSH_USECALLBACK | PSH_NOAPPLYNOW | PSH_HASHELP;
    if (! all_options && workprefs.gfx_afullscreen && workprefs.gfx_width < 640)
	pHeader.hwndParent = NULL;
    else
	pHeader.hwndParent = hAmigaWnd;
    pHeader.hInstance = hInst;
    pHeader.DUN1 pszIcon = MAKEINTRESOURCE (IDI_APPICON);
    pHeader.pszCaption = "WinUAE";
    pHeader.nPages = C_PAGES;
    pHeader.DUN2 nStartPage = 0;
    pHeader.DUN3 ppsp = ppage;
    pHeader.pfnCallback = (PFNPROPSHEETCALLBACK) InitPropertySheet;

    psresult = PropertySheet (&pHeader);

    if( quit_program)
        psresult = -2;
	return psresult;
}

/* fullscreen trackdisplay/powerled code */
#include "xwin.h"

#define TD_PADX 10
#define TD_PADY 4
#define TD_WIDTH 32
#define TD_LED_WIDTH 24
#define TD_LED_HEIGHT 4

#define TD_RIGHT 1
#define TD_BOTTOM 2

static int td_pos = (TD_RIGHT|TD_BOTTOM);

#define TD_NUM_W 7
#define TD_NUM_H 5

static char *numbers = { /* ugly */
"xxxxxx ---xx- -xxxxx xxxxxx x----x xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx "
"x----x ----x- -----x -----x x----x x----- x----- -----x x----x x----x "
"x----x ----x- xxxxxx xxxxxx xxxxxx xxxxxx xxxxxx ----x- xxxxxx xxxxxx "
"x----x ----x- x----- -----x -----x -----x x----x ---x-- x----x -----x "
"xxxxxx ----x- xxxxxx xxxxxx -----x xxxxxx xxxxxx ---x-- xxxxxx xxxxxx " };

static void putpixel(uae_u8 *buf, int i, int j, int c8)
{
switch(gfxvidinfo.pixbytes)
	{
	case 1:
	buf[i * gfxvidinfo.rowbytes + j * gfxvidinfo.pixbytes] = (uae_u8)c8;
	break;
	case 2:
	((uae_u16*)(&buf[i * gfxvidinfo.rowbytes + j * gfxvidinfo.pixbytes]))[0] =
(uae_u16)c8;
	break;
      case 3:
	/* no 24 bit yet */
      break;
	case 4:
	((uae_u32*)(&buf[i * gfxvidinfo.rowbytes + j * gfxvidinfo.pixbytes]))[0] =
(uae_u32)c8;
	break;
}
}

static void write_tdnumber(int x, int y, int num)
{
int i, j;
uae_u8 *numptr, *buf;

numptr = numbers + num * TD_NUM_W;
buf = gfxvidinfo.bufmem + y * gfxvidinfo.rowbytes + x * gfxvidinfo.pixbytes;
for (i = 0; i < TD_NUM_H; i ++) {
	for (j = 0; j < TD_NUM_W; j ++) {
		putpixel(buf,i,j,*numptr=='x'?xcolors[0xfff]:xcolors[0x000]);
		numptr++;
	}
	numptr += 9 * TD_NUM_W;
}
}

void update_fullscreen_gui(void)
{
    int x, y, track, i, j, led, on;
    int on_rgb, off_rgb, c;
    uae_u8 *buf;

    if( td_pos & TD_RIGHT )
        x = gfxvidinfo.width - TD_PADX - 5*TD_WIDTH;
    else
        x = TD_PADX;
    if( td_pos & TD_BOTTOM )
        y = gfxvidinfo.height - TD_PADY - TD_NUM_H - 1 - TD_LED_HEIGHT;
    else y = TD_PADY;

    for (led = 0; led < 5; led++ ) 
    {
	    if (led > 0) 
        {
		    track = gui_data.drive_track[led-1];
		    on = gui_data.drive_motor[led-1];
		    on_rgb = 0x0f0;off_rgb = 0x040;
	    }
        else
        {
		    track = -1;
		    on = gui_data.powerled;
		    on_rgb = 0xf00;off_rgb = 0x400;
	    }
	    c = xcolors[on ? on_rgb : off_rgb];
        if( lockscr() )
        {
	        buf = gfxvidinfo.bufmem + (y + TD_NUM_H + 1 + TD_LED_HEIGHT) *
                gfxvidinfo.rowbytes + (x + (TD_WIDTH - TD_LED_WIDTH) / 2) *
                gfxvidinfo.pixbytes;
	        for (i = 0;i < TD_LED_HEIGHT; i++) 
            {
		        for (j = 0; j < TD_LED_WIDTH; j++) 
                    putpixel(buf,i,j,c);
	        }
	        if (track >= 0) 
            {
		        write_tdnumber(x + (TD_WIDTH - 2 * TD_NUM_W) / 2, y, track/10);
		        write_tdnumber(x + (TD_WIDTH - 2 * TD_NUM_W) / 2 + TD_NUM_W, y, track%10);
	        }
	        x += TD_WIDTH;
            unlockscr();
        }
    }
}

int gui_init (void)
{
    return( GetSettings(1) );
}

int gui_update (void)
{
    return 1;
}

void gui_exit (void)
{
}

extern HWND hStatusWnd;
struct gui_info gui_data;

void gui_led (int led, int on)
{
    WORD type;
    static char drive_text[5*6];
    char *ptr;
    extern int screen_is_picasso;

    if( hStatusWnd )
    {
        if( on )
            type = SBT_POPOUT;
        else
            type = 0;

	    ptr = drive_text + led*6;
        if( led > 0 )
        {
            sprintf( ptr , "%02d", gui_data.drive_track[led-1]);
        }
        else
        {
		    strcpy( ptr, "Power");
        }
        PostMessage (hStatusWnd, SB_SETTEXT, (WPARAM) ((led+2) | type), (LPARAM) ptr);
    }
    else if( currprefs.leds_on_screen && currprefs.gfx_width >= 800 && !screen_is_picasso )
    {
        update_fullscreen_gui();
    }
}

void gui_fps( int fps )
{
    static char fps_text[10];

    if( hStatusWnd )
    {
        sprintf( fps_text, "FPS: %2u", fps+1 );
        PostMessage( hStatusWnd, SB_SETTEXT, (WPARAM)( 1 ), (LPARAM)fps_text );
    }
}

void gui_filename (int num, const char *name)
{
}

void gui_message(const char *format,...)
{
    char msg[2048];
    va_list parms;

    va_start (parms, format);
    vsprintf( msg, format, parms );
    va_end (parms);
    write_log( msg );
    MessageBox( NULL, msg, "WinUAE Error", MB_OK | MB_ICONWARNING | MB_TASKMODAL | MB_SETFOREGROUND );
}
