DIALOG.CXX

/******************************Module*Header*******************************\ 
* Module Name: dialog.cxx
*
* Dialog box functions
*
* Copyright 1995 - 1998 Microsoft Corporation
\**************************************************************************/

#include "pch.c"
#pragma hdrstop

#include <commdlg.h>
#include <commctrl.h>
#include <scrnsave.h>
#include "mazedlg.h"

#include "sscommon.hxx"

// Global string buffers for message box.

// local funtions

static void updateDialogControls(HWND hDlg);

HWND ghDlg; // main dialog window handle
int giSize;
int giImageQual;
BOOL gbTurboMode;
int gnBitsPerPixel;

static void DrawTexture( int surface );
static void CleanUp( HWND hwnd );

// Texture information for each surface: used in both configure and run mode

TEX_INFO gTexInfo[NUM_SURFACES] = {0};

// default surface texture cache
static TEXTURE gDefTex[NUM_DEF_SURFACE_TEXTURES] = {0};

// Per-surface texture information relevant only to configure mode

typedef struct {
TEXTURE userTex;
int iDefTex;
int defTexIDS;
int fileIDS;
int offsetIDS;
int dlgSpinTexID;
int iPalRot; // texture palette rotation index
SS_TEX_BUTTON *pTexBtn; // GL texture drawing button thing
} TEX_DLG;

static TEX_DLG gTex[NUM_SURFACES] = {
{
{0},
BRICK_TEXTURE,
IDS_DEF_WALL_TEXTURE,
IDS_WALL_TEXTURE_FILE,
IDS_WALL_TEXTURE_OFFSET,
DLG_SPIN_WALLS,
NULL
},
{
{0},
WOOD_TEXTURE,
IDS_DEF_FLOOR_TEXTURE,
IDS_FLOOR_TEXTURE_FILE,
IDS_FLOOR_TEXTURE_OFFSET,
DLG_SPIN_FLOOR,
NULL
},
{
{0},
CASTLE_TEXTURE,
IDS_DEF_CEILING_TEXTURE,
IDS_CEILING_TEXTURE_FILE,
IDS_CEILING_TEXTURE_OFFSET,
DLG_SPIN_CEILING,
NULL
}
};

static UINT idTimer = 0;

static BOOL CALLBACK TextureConfigureDialog(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam);

/******************************Public*Routine******************************\
* getIniSettings
*
* - Get the screen saver configuration options from .INI file/registry.
* - Called by both dialog box and screen saver
*
\**************************************************************************/

void
getIniSettings()
{
int option;
int i;

// Load resources

LoadString(hMainInstance, IDS_GENNAME, szScreenSaver,
sizeof(szScreenSaver) / sizeof(TCHAR));

// Get registry settings

if( ss_RegistrySetup( hMainInstance, IDS_SAVERNAME, IDS_INIFILE ) )
{
// get wall/floor/ceiling texture enables
// For now, texturing always on
for( i = 0; i < NUM_SURFACES; i++ )
gTexInfo[i].bTex = TRUE;

option = ss_GetRegistryInt( IDS_DEFAULT_TEXTURE_ENABLE, (1 << NUM_SURFACES)-1 );
for( i = 0; i < NUM_SURFACES; i++, option >>= 1 )
gTexInfo[i].bDefTex = option & 1;

// get default texture indices

for( i = 0; i < NUM_SURFACES; i++ ) {
gTexInfo[i].iDefTex =
ss_GetRegistryInt( gTex[i].defTexIDS, gTex[i].iDefTex );
SS_CLAMP_TO_RANGE2( gTexInfo[i].iDefTex, 0,
NUM_DEF_SURFACE_TEXTURES-1 );
}

// get user texture files

for( i = 0; i < NUM_SURFACES; i++ ) {
ss_GetRegistryString( gTex[i].fileIDS, 0,
gTexInfo[i].texFile.szPathName, MAX_PATH);
gTexInfo[i].texFile.nOffset = ss_GetRegistryInt( gTex[i].offsetIDS, 0 );
}

// get overlay
maze_options.top_view = ss_GetRegistryInt( IDS_OVERLAY, 0 );

// Get rat population
maze_options.nrats = ss_GetRegistryInt(IDS_NRATS, 1);

// get image quality

giImageQual = ss_GetRegistryInt( IDS_IMAGEQUAL, IMAGEQUAL_DEFAULT );
SS_CLAMP_TO_RANGE2( giImageQual, IMAGEQUAL_DEFAULT, IMAGEQUAL_HIGH );

// get size

giSize = ss_GetRegistryInt( IDS_SIZE, 0 );
SS_CLAMP_TO_RANGE2( giSize, MIN_SLIDER, MAX_SLIDER );

// get turbo mode
gbTurboMode = ss_GetRegistryInt( IDS_TURBOMODE, 1 );
}
}


/******************************Public*Routine******************************\
* saveIniSettings
*
* Save the screen saver configuration option to the .INI file/registry.
\**************************************************************************/

static void
saveIniSettings(HWND hDlg)
{
if( ss_RegistrySetup( hMainInstance, IDS_SAVERNAME, IDS_INIFILE ) )
{
int i, option = 0;

// write enables

for( i = NUM_SURFACES-1, option = 0; i >= 0; i--, option <<= 1 )
option |= gTexInfo[i].bDefTex & 1;
ss_WriteRegistryInt( IDS_DEFAULT_TEXTURE_ENABLE, option >>= 1 );

// Write default texture indices

for( i = 0; i < NUM_SURFACES; i++ ) {
ss_WriteRegistryInt( gTex[i].defTexIDS, gTexInfo[i].iDefTex );
}

// write user texture files

for( i = 0; i < NUM_SURFACES; i++ ) {
ss_WriteRegistryString( gTex[i].fileIDS,
gTexInfo[i].texFile.szPathName );
ss_WriteRegistryInt( gTex[i].offsetIDS, gTexInfo[i].texFile.nOffset);
}

// write size
ss_WriteRegistryInt( IDS_SIZE,
ss_GetTrackbarPos(hDlg, DLG_SLIDER_SIZE) );

// write overlay enable
ss_WriteRegistryInt( IDS_OVERLAY, maze_options.top_view );

// Write rat population
ss_WriteRegistryInt( IDS_NRATS, maze_options.nrats );

// write image quality
ss_WriteRegistryInt( IDS_IMAGEQUAL, giImageQual );

// turbot mod
ss_WriteRegistryInt( IDS_TURBOMODE, gbTurboMode );
}
}

/******************************Public*Routine******************************\
* setupDialogControls
*
* Do initial setup of dialog controls.
\**************************************************************************/

static void
setupDialogControls(HWND hDlg)
{
int i;
int idsImageQual;
TCHAR szStr[GEN_STRING_SIZE];

InitCommonControls();

// setup size slider

ss_SetupTrackbar( hDlg, DLG_SLIDER_SIZE, MIN_SLIDER, MAX_SLIDER, 1, 9,
giSize );

// setup default texture spins

for( i = 0; i < NUM_SURFACES; i ++ ) {
SendDlgItemMessage( hDlg, gTex[i].dlgSpinTexID, UDM_SETRANGE, 0,
MAKELONG(NUM_DEF_SURFACE_TEXTURES-1, 0) );
SendDlgItemMessage( hDlg, gTex[i].dlgSpinTexID, UDM_SETPOS, 0,
MAKELONG(gTexInfo[i].iDefTex, 0) );
}

// setup image quality combo box

idsImageQual = IDS_IMAGEQUAL_DEFAULT;
for( i = 0; i < IMAGEQUAL_COUNT; i++, idsImageQual++ ) {
LoadString(hMainInstance, idsImageQual, szStr,
GEN_STRING_SIZE);
SendDlgItemMessage(hDlg, DLG_COMBO_IMAGEQUAL, CB_ADDSTRING, 0,
(LPARAM) szStr);
}
SendDlgItemMessage(hDlg, DLG_COMBO_IMAGEQUAL, CB_SETCURSEL,
giImageQual, 0);

// Disable Quality box when running on > 16 bits per pixel (since it only
// affects dithering)
gnBitsPerPixel = GetDeviceCaps( GetDC(hDlg), BITSPIXEL );
EnableWindow( GetDlgItem(hDlg, DLG_COMBO_IMAGEQUAL), gnBitsPerPixel <= 16 );
EnableWindow( GetDlgItem(hDlg, IDC_STATIC_IMAGEQUAL), gnBitsPerPixel <= 16 );

// set palette rotation index for each surface for a8 textures
for( i = 0; i < NUM_SURFACES; i ++ )
gTex[i].iPalRot = ss_iRand(0xff);

// set state of other controls

CheckDlgButton(hDlg, DLG_CHECK_OVERLAY, maze_options.top_view );

CheckDlgButton(hDlg, DLG_CHECK_TURBOMODE, gbTurboMode );

updateDialogControls(hDlg);
}

/******************************Public*Routine******************************\
* updateDialogControls
*
* Updates dialog controls according to current state
\**************************************************************************/

static void
updateDialogControls(HWND hDlg)
{
int i;
BOOL bDither;

static int dlgSpinTexDef[NUM_SURFACES] = {
DLG_SPIN_WALLS,
DLG_SPIN_FLOOR,
DLG_SPIN_CEILING};

for( i = 0; i < NUM_SURFACES; i ++ ) {
EnableWindow( GetDlgItem(hDlg, gTex[i].dlgSpinTexID), gTexInfo[i].bDefTex );
}

EnableWindow( GetDlgItem(hDlg, DLG_SLIDER_SIZE), !gbTurboMode );
EnableWindow( GetDlgItem(hDlg, IDC_STATIC_SIZE), !gbTurboMode );
EnableWindow( GetDlgItem(hDlg, IDC_STATIC_MIN), !gbTurboMode );
EnableWindow( GetDlgItem(hDlg, IDC_STATIC_MAX), !gbTurboMode );

// Dithering looks bad with turbo mode on and 8 bits/pixel
bDither = (gnBitsPerPixel <= 16) && !gbTurboMode;
EnableWindow( GetDlgItem(hDlg, DLG_COMBO_IMAGEQUAL), bDither );
EnableWindow( GetDlgItem(hDlg, IDC_STATIC_IMAGEQUAL), bDither );
}

/******************************Public*Routine******************************\
* updateGLState
*
\**************************************************************************/

static void
updateGLState()
{
if( giImageQual == IMAGEQUAL_DEFAULT )
glDisable( GL_DITHER );
else
glEnable( GL_DITHER );
}

/******************************Public*Routine******************************\
* ValidateTexture
*
*
\**************************************************************************/

static TEXTURE *
ValidateTexture( int surface )
{
TEXTURE *pTex = NULL;
TEX_INFO *pTexInfo = &gTexInfo[surface];
extern TEX_RES gTexResSurf[]; // from glmaze.c

if( !pTexInfo->bDefTex ) {
// Try to draw user texture
pTex = &gTex[surface].userTex;
if( !pTex->data ) {
// Load user texture - this can fail!
// If nOffset = 0, we assume user has never specified a texture,
// so we silently switch to the default texture.
// If the load of user texture fails, we use default texture
if( (pTexInfo->texFile.nOffset == 0) ||
(! ss_LoadTextureFile( &pTexInfo->texFile, pTex )) ) {

pTexInfo->bDefTex = TRUE; // draw default texture resource

// Enable the spin control
EnableWindow( GetDlgItem(ghDlg, gTex[surface].dlgSpinTexID),
TRUE );
}
}
}

if( pTexInfo->bDefTex ) {
// Draw default texture resource
pTex = &gDefTex[pTexInfo->iDefTex];
if( !pTex->data ) {
if( !ss_LoadTextureResource( &gTexResSurf[pTexInfo->iDefTex], pTex ))
pTex = NULL;
}
}

return pTex;
}

/******************************Public*Routine******************************\
* DrawTextures
*
* Draw all the textures
*
\**************************************************************************/

static void
DrawTextures()
{
for( int i = 0; i < NUM_SURFACES; i++ ) {
DrawTexture( i );
}
}

/******************************Public*Routine******************************\
* DrawTexture
*
* Draw appropriate texture in supplied window (e.g. a button)
* - Use TEX_INFO state to determine texture
* - Load texture if not in cache
*
\**************************************************************************/

static void
DrawTexture( int surface )
{
TEXTURE *pTex;

// Make sure valid texture loaded for this surface
if( ! (pTex = ValidateTexture( surface )) )
return;

SS_TEX_BUTTON *pTexBtn = gTex[surface].pTexBtn;
// pTexBtn never NULL, else ss_ConfigInit fails

// If palette rotation for this texture, slam in the current rotation,
// to be used by pTexBtn->Draw
if( pTex->pal )
pTex->iPalRot = gTex[surface].iPalRot;

pTexBtn->Draw( pTex );
}

/******************************Public*Routine******************************\
* RegisterDialogClasses
*
\**************************************************************************/

BOOL WINAPI RegisterDialogClasses(HANDLE hinst)
{
return TRUE;
}

/******************************Public*Routine******************************\
* HandlePreviewDraw
*
\**************************************************************************/

static BOOL
HandlePreviewDraw( UINT idCtl, LPDRAWITEMSTRUCT lpdis )
{
int surface = DLG_PREVIEW_TO_SURFACE( idCtl );

if( lpdis->itemAction == ODA_DRAWENTIRE ) {
DrawTexture( surface );
return TRUE;
}
return FALSE;
}

/******************************Public*Routine******************************\
* HandleTexButtonNewTexture
*
* - Handle when a user selects a new texture
*
* If the new texture fails to load (unlikely, since we validate a good chunk
* of it with the selection dialog), then the current default texture is
* used.
\**************************************************************************/

static void
HandleTexButtonNewTexture( int surface )
{
TEXTURE *pTex = &gTex[surface].userTex;

// Delete the old texture
ss_DeleteTexture( pTex );

// Load up the new texture
if( ! ss_LoadTextureFile( &gTexInfo[surface].texFile, pTex ) )
gTexInfo[surface].bDefTex = TRUE;
}

/******************************Public*Routine******************************\
* MazeDlgTimerProc
*
* Runs off of WM_TIMER message. Used for any gl animation in the dialog
*
\**************************************************************************/

static void
MazeDlgTimerProc()
{
extern TEX_RES gTexResSurf[]; // from glmaze.c

if( ss_PalettedTextureEnabled() ) {
TEX_INFO *pti = gTexInfo;
int i;

// rotate texture palettes for surfaces with a8 palettes

for( i = 0; i < NUM_SURFACES; i++, pti++ ) {
if( pti->bTex &&
pti->bDefTex &&
( gTexResSurf[pti->iDefTex].type == TEX_A8 ) )
{
// Increment palette rotation for this surface
gTex[i].iPalRot++;
// Draw texture associated with the surface
DrawTexture( i );
}
}
}
}

/******************************Public*Routine******************************\
* ConfigInit
*
* Do Initialization for Config mode
*
* This is the config equivalent of ss_Init
*
* Setup SS_TEX_BUTTON wrappers for each of the 3 texture preview buttons.
\**************************************************************************/

BOOL
ss_ConfigInit( HWND hDlg )
{
SS_DBGLEVEL1( SS_LEVEL_INFO, "ConfigInit for %d\n", hDlg );

// Create GL texture buttons to draw the surface previews

SS_TEX_BUTTON *pTexBtn;

for( int i = 0; i < NUM_SURFACES; i++ ) {
pTexBtn = new SS_TEX_BUTTON( hDlg,
GetDlgItem(hDlg, DLG_SURFACE_TO_PREVIEW(i)) );
if( !pTexBtn ) {
return FALSE;
}
gTex[i].pTexBtn = pTexBtn;
}

updateGLState();

// Start a timer for animating texture palettes
idTimer = 1;
SetTimer(hDlg, idTimer, 16, 0);

// Note: no textures are loaded here, they are 'demand-loaded'
return TRUE;
}

/******************************Public*Routine******************************\
* ScreenSaverConfigureDialog
*
* Processes messages for the configuration dialog box.
*
\**************************************************************************/

BOOL ScreenSaverConfigureDialog(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
int wTmp, surface;
static BOOL bInited = 0;

switch (message) {
case WM_INITDIALOG:
getIniSettings();
setupDialogControls(hDlg);
// cache the window handle
ghDlg = hDlg;
return TRUE;

case WM_TIMER:
MazeDlgTimerProc();
return 0;
break;

case WM_DRAWITEM:
switch( (UINT) wParam ) {
case DLG_PREVIEW_WALLS:
case DLG_PREVIEW_FLOOR:
case DLG_PREVIEW_CEILING:
if( HandlePreviewDraw( (UINT) wParam,
(LPDRAWITEMSTRUCT) lParam ) )
return TRUE;
default:
break;
}
break;

case WM_VSCROLL:
switch(LOWORD(wParam))
{
case SB_THUMBPOSITION:
// get new value
wTmp = HIWORD(wParam);
{
int id;
HWND hwndScroll = (HWND) lParam;

id = GetDlgCtrlID( hwndScroll );
surface = DLG_SPIN_TEX_TO_SURFACE( id );
gTexInfo[surface].iDefTex = wTmp;
DrawTexture( surface );
}
break;
default:
break;
}
break;

case WM_COMMAND:
switch (LOWORD(wParam)) {

case DLG_BUTTON_WALLS_TEX:
case DLG_BUTTON_FLOOR_TEX:
case DLG_BUTTON_CEILING_TEX:
surface = DLG_BUTTON_TEX_TO_SURFACE( LOWORD(wParam) );
if( DialogBoxParam(
hMainInstance,
(LPTSTR) MAKEINTRESOURCE( DLG_TEXTURE_CONFIGURE ),
hDlg, (DLGPROC) TextureConfigureDialog, surface ) ) {
// If anything changed here, we have to draw it, as it
// seems when choose texture dialog box terminates, we
// don't get any DRAW_ITEM messages.
// Draw preview area
DrawTexture( surface );
}
break;

case DLG_CHECK_OVERLAY:
maze_options.top_view = !maze_options.top_view;
CheckDlgButton(hDlg, DLG_CHECK_OVERLAY,
maze_options.top_view );
break;

case DLG_CHECK_TURBOMODE:
gbTurboMode = !gbTurboMode;
CheckDlgButton(hDlg, DLG_CHECK_TURBOMODE, gbTurboMode );
break;

case DLG_COMBO_IMAGEQUAL:
switch (HIWORD(wParam))
{
case CBN_EDITCHANGE:
case CBN_SELCHANGE:
{
int oldImageQual = giImageQual;
giImageQual =
SendDlgItemMessage(hDlg, DLG_COMBO_IMAGEQUAL,
CB_GETCURSEL, 0, 0);
if( giImageQual != oldImageQual ) {
// change has occurred - redraw any gl objects
updateGLState();
DrawTextures();
}
}
break;
default:
return FALSE;
}
break;

case IDOK:
saveIniSettings(hDlg);
// fall thru...

case IDCANCEL:
CleanUp( hDlg );
EndDialog(hDlg, FALSE);
break;

default:
return 0;
break;
}
updateDialogControls(hDlg);
return TRUE;
break;

default:
return 0;
}
return 0;
}


/******************************Public*Routine******************************\
* updateTextureConfigControls
*
* Updates dialog controls according to current state
*
\**************************************************************************/

static void
updateTextureConfigControls(HWND hDlg, BOOL bDefTex )
{
CheckDlgButton(hDlg, IDC_RADIO_TEX_DEFAULT, bDefTex );
CheckDlgButton(hDlg, IDC_RADIO_TEX_CHOOSE, !bDefTex );

EnableWindow(GetDlgItem(hDlg, DLG_BUTTON_TEX_CHOOSE ), !bDefTex );
}

/******************************Public*Routine******************************\
* TextureConfigureDialog
*
* Processes messages for the texture configure dialog box.
*
* - Call EndDialog with TRUE if texture changed, otherwise FALSE
*
\**************************************************************************/

static BOOL CALLBACK
TextureConfigureDialog(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
// static state ok here, cuz only one of these dialogs can be active
static int surface;
static BOOL bDefTex; // temporary state

switch (message) {
case WM_INITDIALOG:
// Cache some initial values
surface = (int) lParam;
bDefTex = gTexInfo[surface].bDefTex;
updateTextureConfigControls(hDlg, bDefTex );
return TRUE;

case WM_COMMAND:
switch (LOWORD(wParam)) {

case DLG_BUTTON_TEX_CHOOSE:
if( ss_SelectTextureFile( hDlg,
&gTexInfo[surface].texFile ) ) {
// New user texture was selected
HandleTexButtonNewTexture( surface );

// For now, let's end the dialog right here if a
// new one chosen - otherwise we'd have to make the
// new texture discardable if user entered Cancel
EndDialog(hDlg, TRUE );
}
break;

case IDC_RADIO_TEX_DEFAULT:
bDefTex = TRUE;
break;

case IDC_RADIO_TEX_CHOOSE:
bDefTex = FALSE;
break;

case IDOK:
// save state
gTexInfo[surface].bDefTex = bDefTex;
EndDialog(hDlg, TRUE);
break;

case IDCANCEL:
EndDialog(hDlg, FALSE);
break;

default:
return 0;
break;
}
updateTextureConfigControls(hDlg, bDefTex );
return TRUE;
break;

default:
return 0;
}
return 0;
}

/******************************Public*Routine******************************\
* CleanUp
*
\**************************************************************************/

static void
CleanUp( HWND hwnd )
{
int i;

if (idTimer) {
KillTimer(hwnd, idTimer);
idTimer = 0;
}

// delete any textures and tex buttons created

for( i = 0; i < NUM_SURFACES; i ++ ) {
if( gTex[i].userTex.data )
ss_DeleteTexture( &gTex[i].userTex );
if( gDefTex[i].data )
ss_DeleteTexture( &gDefTex[i] );
if( gTex[i].pTexBtn )
delete gTex[i].pTexBtn;
}

}