xwords/xwords4/wince/cemain.c

2323 lines
69 KiB
C
Raw Normal View History

2003-11-20 17:26:35 +01:00
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
/*
* Copyright 2002-2004 by Eric House (fixin@peak.org). All rights reserved.
2003-11-20 17:26:35 +01:00
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Derived from code generated by M$'s eVC++.
2003-11-20 17:26:35 +01:00
*/
#include "stdafx.h"
#include "xwords4.h"
#include <commctrl.h>
#include <commdlg.h>
#include <stdio.h>
#include <winuser.h>
2004-12-17 08:45:30 +01:00
#include <aygshell.h>
2003-11-20 17:26:35 +01:00
#include "strutils.h"
#include "memstream.h"
#include "cemain.h"
#include "cedefines.h"
#include "ceginfo.h"
#include "cestrbx.h"
#include "cedict.h"
#include "ceblank.h"
#include "ceprefs.h"
#include "ceaskpwd.h"
#include "ceutil.h"
#include "ceir.h"
2004-03-28 03:14:34 +02:00
#include "ceclrsel.h"
2004-07-10 19:46:36 +02:00
#include "cehntlim.h"
2003-11-20 17:26:35 +01:00
#include "LocalizedStrIncludes.h"
#define MAX_LOADSTRING 100
/* #define PREFSFILENAME L"\\My Documents\\Personal\\.xwprefs" */
/* #define UNSAVEDGAMEFILENAME "\\My Documents\\Personal\\_newgame" */
#define DEFAULT_DIR_NAME L"\\My Documents\\Crosswords"
/* #define PREFSFILENAME L"\\My Documents\\Crosswords\\.xwprefs" */
#define PREFSFILENAME L"\\My Documents\\Crosswords\\xwprefs"
#define UNSAVEDGAMEFILENAME "\\My Documents\\Crosswords\\_newgame"
#define SCROLLBAR_WIDTH 12
#define SCROLLBARID 0x4321 /* needs to be unique! */
2003-11-20 17:26:35 +01:00
/* CE_DEBUG_SAVEOFTEN: Temporary hack to attempt to get a reproducible case
* of the lockup folks are seeing on WM 2003 SE devices.
*/
#define CE_DEBUG_SAVEOFTEN
2003-11-20 17:26:35 +01:00
#ifdef MEM_DEBUG
# define MEMPOOL globals->mpool,
#else
# define MEMPOOL
#endif
typedef struct FileWriteState {
CEAppGlobals* globals;
XP_UCHAR* path;
} FileWriteState;
/* forward util function decls */
static VTableMgr* ce_util_getVTManager( XW_UtilCtxt* uc );
static void ce_util_userError( XW_UtilCtxt* uc, UtilErrID id );
static XP_Bool ce_util_userQuery( XW_UtilCtxt* uc, UtilQueryID id,
XWStreamCtxt* stream );
2003-11-20 17:26:35 +01:00
static XWBonusType ce_util_getSquareBonus( XW_UtilCtxt* uc,
ModelCtxt* model,
XP_U16 col, XP_U16 row );
static XP_S16 ce_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi,
2003-11-20 17:26:35 +01:00
XP_U16 playerNum,
const XP_UCHAR4* texts, XP_U16 nTiles );
2003-11-20 17:26:35 +01:00
static XP_Bool ce_util_askPassword( XW_UtilCtxt* uc, const XP_UCHAR* name,
XP_UCHAR* buf, XP_U16* len );
static void ce_util_trayHiddenChange( XW_UtilCtxt* uc, XP_Bool nowHidden );
static void ce_util_yOffsetChange( XW_UtilCtxt* uc, XP_U16 oldOffset,
XP_U16 newOffset );
static void ce_util_notifyGameOver( XW_UtilCtxt* uc );
static XP_Bool ce_util_hiliteCell( XW_UtilCtxt* uc, XP_U16 col,
XP_U16 row );
static XP_Bool ce_util_engineProgressCallback( XW_UtilCtxt* uc );
static void ce_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why );
static void ce_util_requestTime( XW_UtilCtxt* uc );
static XP_U32 ce_util_getCurSeconds( XW_UtilCtxt* uc );
static DictionaryCtxt* ce_util_makeEmptyDict( XW_UtilCtxt* uc );
#ifndef XWFEATURE_STANDALONE_ONLY
static XWStreamCtxt* ce_util_makeStreamFromAddr( XW_UtilCtxt* uc,
XP_U16 channelNo );
#endif
static XP_UCHAR* ce_util_getUserString( XW_UtilCtxt* uc, XP_U16 stringCode );
static XP_Bool ce_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost );
2004-07-10 19:46:36 +02:00
#ifdef XWFEATURE_SEARCHLIMIT
static XP_Bool ce_util_getTraySearchLimits( XW_UtilCtxt* uc, XP_U16* min,
XP_U16* max );
#endif
2003-11-20 17:26:35 +01:00
#ifdef SHOW_PROGRESS
static void ce_util_engineStarting( XW_UtilCtxt* uc );
static void ce_util_engineStopping( XW_UtilCtxt* uc );
#endif
static void notImpl( CEAppGlobals* globals );
static void messageBoxChar( CEAppGlobals* globals, XP_UCHAR* str,
wchar_t* title );
static XP_Bool queryBoxChar( CEAppGlobals* globals, XP_UCHAR* msg );
static XP_Bool ceMsgFromStream( CEAppGlobals* globals, XWStreamCtxt* stream,
wchar_t* title, XP_Bool isQuery,
XP_Bool destroy );
2003-11-20 17:26:35 +01:00
static void RECTtoXPR( XP_Rect* dest, RECT* src );
static XP_Bool doNewGame( CEAppGlobals* globals, XP_Bool silent );
static XP_Bool ceSaveCurGame( CEAppGlobals* globals, XP_Bool autoSave );
static void updateForColors( CEAppGlobals* globals );
2003-11-20 17:26:35 +01:00
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass (HINSTANCE, LPTSTR);
BOOL InitInstance (HINSTANCE, int);
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK About (HWND, UINT, WPARAM, LPARAM);
int WINAPI
WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow)) {
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_XWORDS4);
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// It is important to call this function so that the application
// will get 'well formed' small icons associated with it.
//
ATOM
MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(CEAppGlobals*);
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_XWORDS4));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}
#define N_TOOLBAR_BUTTONS 4
2003-11-20 17:26:35 +01:00
static void
addButtonsToCmdBar( CEAppGlobals* globals )
{
XP_Bool success;
XP_U16 i;
int index;
int cmds[N_TOOLBAR_BUTTONS] = { FLIP_BUTTON_ID, VALUE_BUTTON_ID,
HINT_BUTTON_ID, JUGGLE_BUTTON_ID };
2003-11-20 17:26:35 +01:00
int resIDs[N_TOOLBAR_BUTTONS] = { IDB_FLIPBUTTON, IDB_VALUESBUTTON,
IDB_HINTBUTTON, IDB_JUGGLEBUTTON };
2003-11-20 17:26:35 +01:00
TBBUTTON buttData = {
0, /*iBitmap; */
0, //FLIP_BUTTON_ID,
TBSTATE_ENABLED, /* state */
TBSTYLE_BUTTON,
0,
-1
};
for ( i = 0; i < N_TOOLBAR_BUTTONS; ++i ) {
index = CommandBar_AddBitmap(globals->hwndCB, globals->hInst,
resIDs[i], 1, 16, 16 );
buttData.iBitmap = index;
buttData.idCommand = cmds[i];
success = CommandBar_InsertButton( globals->hwndCB, -1, &buttData );
}
} /* addButtonsToCmdBar */
static void
ceInitUtilFuncs( CEAppGlobals* globals )
{
UtilVtable* vtable = globals->util.vtable =
XP_MALLOC( globals->mpool, sizeof( UtilVtable ) );
globals->util.closure = (void*)globals;
globals->util.gameInfo = &globals->gameInfo;
MPASSIGN( globals->util.mpool, globals->mpool );
vtable->m_util_getVTManager = ce_util_getVTManager;
vtable->m_util_userError = ce_util_userError;
vtable->m_util_getSquareBonus = ce_util_getSquareBonus;
vtable->m_util_userQuery = ce_util_userQuery;
vtable->m_util_userPickTile = ce_util_userPickTile;
vtable->m_util_askPassword = ce_util_askPassword;
vtable->m_util_trayHiddenChange = ce_util_trayHiddenChange;
vtable->m_util_yOffsetChange = ce_util_yOffsetChange;
vtable->m_util_notifyGameOver = ce_util_notifyGameOver;
vtable->m_util_hiliteCell = ce_util_hiliteCell;
vtable->m_util_engineProgressCallback = ce_util_engineProgressCallback;
vtable->m_util_setTimer = ce_util_setTimer;
vtable->m_util_requestTime = ce_util_requestTime;
vtable->m_util_getCurSeconds = ce_util_getCurSeconds;
vtable->m_util_makeEmptyDict = ce_util_makeEmptyDict;
vtable->m_util_getUserString = ce_util_getUserString;
vtable->m_util_warnIllegalWord = ce_util_warnIllegalWord;
2004-07-10 19:46:36 +02:00
#ifdef XWFEATURE_SEARCHLIMIT
vtable->m_util_getTraySearchLimits = ce_util_getTraySearchLimits;
#endif
2003-11-20 17:26:35 +01:00
#ifdef SHOW_PROGRESS
vtable->m_util_engineStarting = ce_util_engineStarting;
vtable->m_util_engineStopping = ce_util_engineStopping;
#endif
} /* ceInitUtilFuncs */
#ifdef CEFEATURE_CANSCROLL
# define SCROLL_SHRINK 1
static void
showScroller( CEAppGlobals* globals, XP_U16 nHidden, XP_U16 x, XP_U16 y,
XP_U16 width, XP_U16 height )
{
if ( !globals->scrollHandle ) {
HWND hwndSB;
SCROLLINFO sinfo;
int ret;
hwndSB = CreateWindow( TEXT("SCROLLBAR"), // Class name
NULL, // Window text
// Window style
SBS_VERT|WS_VISIBLE|WS_CHILD,
x + SCROLL_SHRINK, y,
width - SCROLL_SHRINK, height + 1,
globals->hWnd,
(HMENU)SCROLLBARID,// The control identifier
globals->hInst, // The instance handle
NULL ); // s'pposed to be NULL
XP_MEMSET( &sinfo, 0, sizeof(sinfo) );
sinfo.cbSize = sizeof(sinfo);
sinfo.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
sinfo.nPos = 0;
sinfo.nMin = 0;
sinfo.nMax = nHidden;
sinfo.nPage = 1;
ret = SetScrollInfo( hwndSB, SB_CTL, &sinfo, TRUE );
EnableWindow( hwndSB, TRUE ); /* tray hidden */
globals->scrollHandle = hwndSB;
}
ShowWindow( globals->scrollHandle, SW_SHOW );
} /* showScroller */
static void
hideScroller( CEAppGlobals* globals )
{
if ( !!globals->scrollHandle ) {
ShowWindow( globals->scrollHandle, SW_HIDE );
}
/* else there's nothing to do */
}
#endif
#define MIN_CELL_WIDTH 12
#define MIN_CELL_HEIGHT 12
#define MIN_TRAY_HEIGHT 20
#define TRAY_PADDING 1
typedef struct CEBoardParms {
XP_U16 boardHScale;
XP_U16 boardVScale;
XP_U16 trayTop;
XP_U16 trayVScale;
XP_U16 trayHScale;
XP_U16 leftEdge;
XP_U16 scoreWidth;
XP_U16 scoreHeight;
XP_Bool needsScroller;
} CEBoardParms;
static void
figureBoardParms( CEAppGlobals* globals, XP_U16 nCols, CEBoardParms* bparms )
{
RECT rc;
XP_U16 width, height;
XP_U16 trayVScale, leftEdge, scoreWidth;
XP_U16 boardHt, boardWidth, visBoardHt, hScale, vScale, nHiddenRows;
XP_U16 boardHtLimit, trayTop;
XP_Bool needsScroller;
GetClientRect( globals->hWnd, &rc );
width = rc.right - rc.left;
height = rc.bottom - rc.top;
boardHt = height - CE_SCORE_HEIGHT - MIN_TRAY_HEIGHT;
/* Try to make it fit without scrolling. But if necessary, reduce the
width for a scrollbar. */
vScale = boardHt / nCols;
needsScroller = vScale < MIN_CELL_HEIGHT;
if ( needsScroller ) {
vScale = MIN_CELL_HEIGHT;
}
boardWidth = width;
if ( needsScroller ) {
boardWidth -= SCROLLBAR_WIDTH;
}
hScale = boardWidth / nCols;
/* Figure tray top. May overlap board. The tray's height must be at
least the minimum, plus whatever fraction of a row is left when
visible board height is determined. */
visBoardHt = vScale * nCols;
nHiddenRows = 0;
boardHtLimit = height - CE_SCORE_HEIGHT - MIN_TRAY_HEIGHT;
while ( visBoardHt > boardHtLimit ) {
visBoardHt -= vScale;
++nHiddenRows;
}
trayTop = CE_SCORE_HEIGHT + visBoardHt + TRAY_PADDING;
trayVScale = height - trayTop;
/* Center the board */
boardWidth = nCols * hScale;
if ( needsScroller ) {
boardWidth += SCROLLBAR_WIDTH;
}
leftEdge = (width - boardWidth) / 2; /* center it all */
scoreWidth = width;
if ( globals->gameInfo.timerEnabled ) {
scoreWidth -= CE_TIMER_WIDTH;
}
bparms->boardHScale = hScale;
bparms->boardVScale = vScale;
bparms->trayTop = trayTop;
bparms->trayVScale = trayVScale;
bparms->trayHScale = CE_TRAY_SCALEH; /* unchanged so far... */
bparms->leftEdge = leftEdge;
bparms->scoreWidth = scoreWidth;
bparms->scoreHeight = CE_SCORE_HEIGHT;
#ifdef CEFEATURE_CANSCROLL
bparms->needsScroller = needsScroller;
if ( needsScroller ) {
XP_U16 boardRight = leftEdge + (nCols * hScale);
showScroller( globals, nHiddenRows,
boardRight,
CE_SCORE_HEIGHT,
rc.right - boardRight, visBoardHt );
XP_LOGF( "NEEDING SCROLLBAR!!!!" );
XP_LOGF( "%d rows hidden", nHiddenRows );
} else {
hideScroller( globals );
}
globals->nHiddenRows = nHiddenRows;
#endif
} /* figureBoardParms */
2003-11-20 17:26:35 +01:00
static XP_Bool
cePositionBoard( CEAppGlobals* globals )
{
XP_Bool erase = XP_FALSE;
XP_U16 nCols;
CEBoardParms bparms;
2003-11-20 17:26:35 +01:00
XP_ASSERT( !!globals->game.model );
nCols = model_numCols( globals->game.model );
XP_ASSERT( nCols <= CE_MAX_ROWS );
figureBoardParms( globals, nCols, &bparms );
2003-11-20 17:26:35 +01:00
board_setTimerLoc( globals->game.board, CE_TIMER_LEFT,
CE_TIMER_TOP, CE_TIMER_WIDTH, CE_TIMER_HEIGHT );
board_setPos( globals->game.board, bparms.leftEdge,
bparms.scoreHeight, XP_FALSE );
board_setScale( globals->game.board, bparms.boardHScale, bparms.boardVScale );
2003-11-20 17:26:35 +01:00
board_setScoreboardLoc( globals->game.board, CE_SCORE_LEFT,
CE_SCORE_TOP, bparms.scoreWidth,
bparms.scoreHeight, XP_TRUE );
2003-11-20 17:26:35 +01:00
board_setShowColors( globals->game.board, globals->appPrefs.showColors );
2005-01-23 09:15:29 +01:00
board_setYOffset( globals->game.board, 0 );
2003-11-20 17:26:35 +01:00
board_prefsChanged( globals->game.board, &globals->appPrefs.cp );
board_setTrayLoc( globals->game.board,
CE_TRAY_LEFT_RH,
bparms.trayTop,
bparms.trayHScale, bparms.trayVScale,
2003-11-20 17:26:35 +01:00
CE_DIVIDER_WIDTH );
server_prefsChanged( globals->game.server, &globals->appPrefs.cp );
return erase;
} /* cePositionBoard */
/* Set the title to be app-name COLON file-name. If there's no colon there
* now append colon and game name. Else if there is a color replace what
* follows it with the new name.
*/
static void
ceSetTitleFromName( CEAppGlobals* globals )
{
wchar_t widebuf[256];
wchar_t* colonPos;
XP_UCHAR* baseStart;
XP_UCHAR* gameName;
XP_U16 len = (XP_U16)SendMessage( globals->hWnd, WM_GETTEXT,
sizeof(widebuf), (long)widebuf );
colonPos = wcsstr( widebuf, L":" );
if ( colonPos == NULL ) {
wcscat( widebuf, L":" );
colonPos = widebuf + len; /* we'll write at the end */
}
++colonPos; /* skip the colon */
gameName = globals->curGameName;
baseStart = strrchr( gameName, '\\' );
++baseStart;
len = (XP_U16)XP_STRLEN( baseStart );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, baseStart, len + 1,
colonPos, len + 1 );
/* now get rid of the ".xwg" */
colonPos = wcsrchr( widebuf, '.' );
if ( colonPos != NULL ) {
*colonPos = 0;
}
SendMessage( globals->hWnd, WM_SETTEXT, 0, (long)widebuf );
} /* ceSetTitleFromName */
static void
ceInitAndStartBoard( CEAppGlobals* globals, XP_Bool newGame, CeGamePrefs* gp )
{
DictionaryCtxt* dict;
XP_UCHAR* newDictName = globals->gameInfo.dictName;
/* This needs to happen even when !newGame because it's how the dict
slots in PlayerInfo get loaded. That really ought to happen earlier,
though. */
XP_ASSERT( !!globals->game.model );
dict = model_getDictionary( globals->game.model );
if ( !!dict ) {
XP_UCHAR* curDictName = dict_getName( dict );
if ( !!newDictName &&
( !curDictName || 0 != strcmp( curDictName, newDictName ) ) ) {
dict_destroy( dict );
dict = NULL;
} else {
replaceStringIfDifferent( MEMPOOL &globals->gameInfo.dictName,
curDictName );
}
}
if ( !dict ) {
#ifdef STUBBED_DICT
dict = make_stubbed_dict( MPPARM_NOCOMMA(globals->mpool) );
#else
2004-01-17 23:10:23 +01:00
XP_ASSERT( !!newDictName );
2003-11-20 17:26:35 +01:00
XP_DEBUGF( "calling ce_dictionary_make" );
dict = ce_dictionary_make( globals, copyString( MEMPOOL newDictName ));
#endif
XP_ASSERT( !!dict );
model_setDictionary( globals->game.model, dict );
}
if ( newGame ) {
XP_U16 newGameID = 0;
game_reset( MEMPOOL &globals->game, &globals->gameInfo, &globals->util,
2004-01-17 23:10:23 +01:00
newGameID, &globals->appPrefs.cp, (TransportSend)NULL,
globals );
2003-11-20 17:26:35 +01:00
if ( !!gp ) {
globals->gameInfo.hintsNotAllowed = gp->hintsNotAllowed;
globals->gameInfo.robotSmartness = gp->robotSmartness;
}
}
XP_ASSERT( !!globals->game.board );
(void)cePositionBoard( globals );
board_invalAll( globals->game.board );
InvalidateRect( globals->hWnd, NULL, TRUE /* erase */ );
server_do( globals->game.server );
globals->isNewGame = FALSE;
} /* ceInitAndStartBoard */
#ifdef DEBUG
void
logLastError( XP_UCHAR* comment )
{
LPVOID lpMsgBuf;
DWORD lastErr = GetLastError();
XP_UCHAR msg[256];
XP_U16 len;
XP_U16 lenSoFar;
strcpy( msg, comment );
strcat( msg, ": " );
lenSoFar = strlen( msg );
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
lastErr,
0, // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
len = wcslen( lpMsgBuf );
if ( len >= sizeof(msg)-lenSoFar ) {
len = sizeof(msg) - lenSoFar - 1;
}
WideCharToMultiByte( CP_ACP, 0, lpMsgBuf, len + 1,
msg + lenSoFar, len + 1, NULL, NULL );
LocalFree( lpMsgBuf );
XP_LOGF( "system error: %s", msg );
} /* logLastError */
#endif
2003-11-20 17:26:35 +01:00
static void
ceSavePrefs( CEAppGlobals* globals )
{
HANDLE fileH;
fileH = CreateFile( PREFSFILENAME, GENERIC_WRITE, 0, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_HIDDEN, NULL );
2003-11-20 17:26:35 +01:00
if ( fileH != INVALID_HANDLE_VALUE ) {
XP_U32 nWritten;
XP_U16 nameLen = 0;
XP_UCHAR* name = globals->curGameName;
if ( name != NULL ) {
nameLen = (XP_U16)XP_STRLEN( name );
}
SetFilePointer( fileH, 0, 0, FILE_BEGIN );
/* write prefs, including version num */
WriteFile( fileH, &globals->appPrefs, sizeof(globals->appPrefs),
&nWritten, NULL );
XP_DEBUGF( "sizeof(appPrefs) => %ld", sizeof( globals->appPrefs ) );
WriteFile( fileH, &nameLen, sizeof(nameLen), &nWritten, NULL );
WriteFile( fileH, name, nameLen, &nWritten, NULL );
SetEndOfFile( fileH ); /* truncate anything previously there */
XP_DEBUGF( "ceSavePrefs: prefs file written" );
} else {
logLastError( "failed to create prefs file" );
2003-11-20 17:26:35 +01:00
}
} /* ceSavePrefs */
static XP_Bool
ceLoadPrefs( CEAppGlobals* globals )
{
XP_Bool result = XP_FALSE;
HANDLE fileH;
fileH = CreateFile( PREFSFILENAME, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
2003-11-20 17:26:35 +01:00
if ( fileH != INVALID_HANDLE_VALUE ) {
XP_U32 fileSize = GetFileSize( fileH, NULL );
XP_DEBUGF( "ceLoadPrefs: prefs file found" );
if ( fileSize >= sizeof( CEAppPrefs ) ) {
CEAppPrefs tmpPrefs;
XP_U32 bytesRead;
XP_U16 nameLen;
XP_UCHAR* name;
if ( ReadFile( fileH, &tmpPrefs, sizeof(tmpPrefs),
&bytesRead, NULL ) ) {
if ( tmpPrefs.versionFlags == CUR_CE_PREFS_FLAGS ) {
XP_MEMCPY( &globals->appPrefs, &tmpPrefs,
sizeof(globals->appPrefs) );
result = XP_TRUE;
ReadFile( fileH, &nameLen, sizeof(nameLen), &bytesRead, NULL );
name = XP_MALLOC( globals->mpool, nameLen + 1 );
ReadFile( fileH, name, nameLen, &bytesRead, NULL );
name[nameLen] = '\0';
globals->curGameName = name;
XP_DEBUGF( "loaded saved name: %s", name );
}
}
}
CloseHandle( fileH );
} else {
XP_LOGF( "ceLoadPrefs: prefs file not found" );
2003-11-20 17:26:35 +01:00
}
return result; /* none found */
} /* ceLoadPrefs */
static XWStreamCtxt*
make_generic_stream( CEAppGlobals* globals )
{
return mem_stream_make( MPPARM(globals->mpool) globals->vtMgr,
globals, 0, NULL );
} /* make_generic_stream */
2003-11-20 17:26:35 +01:00
static XWStreamCtxt*
fileToStream( CEAppGlobals* globals, XP_UCHAR* path )
{
XWStreamCtxt* stream = NULL;
HANDLE fileH;
wchar_t widebuf[257];
XP_U16 len;
XP_DEBUGF( "fileToStream" );
len = (XP_U16)XP_STRLEN( path );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, path, len + 1,
widebuf, len + 1 );
fileH = CreateFile( widebuf, GENERIC_READ, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
if ( fileH != INVALID_HANDLE_VALUE ) {
XP_U32 len = GetFileSize( fileH, NULL );
XP_U32 nRead;
XP_UCHAR* buf = XP_MALLOC( globals->mpool, len );
XP_DEBUGF( "fileSize = %ld", len );
ReadFile( fileH, buf, len, &nRead, NULL );
CloseHandle( fileH );
stream = make_generic_stream( globals );
2003-11-20 17:26:35 +01:00
stream_open( stream );
stream_putBytes( stream, buf, (XP_U16)nRead );
XP_FREE( globals->mpool, buf );
}
XP_DEBUGF( "fileToStream => 0x%lx", (unsigned long)stream );
return stream;
} /* fileToStream */
static void
ceSaveGamePrefs( CEAppGlobals* globals, XWStreamCtxt* stream )
{
} /* ceSaveGamePrefs */
2003-11-20 17:26:35 +01:00
static void
ceLoadGamePrefs( CEAppGlobals* globals, XWStreamCtxt* stream )
{
XP_DEBUGF( "ceLoadGamePrefs" );
} /* ceLoadGamePrefs */
static XP_Bool
ceLoadSavedGame( CEAppGlobals* globals )
{
XP_Bool success = XP_FALSE;
XWStreamCtxt* stream;
XP_DEBUGF( "ceLoadSavedGame" );
stream = fileToStream( globals, globals->curGameName );
success = stream != NULL;
if ( success ) {
DictionaryCtxt* dict;
XP_Bool hasDict;
ceLoadGamePrefs( globals, stream );
hasDict = stream_getU8( stream );
if ( hasDict ) {
2004-01-17 23:10:23 +01:00
#ifdef STUBBED_DICT
XP_ASSERT(0); /* just don't do this!!!! */
#else
2003-11-20 17:26:35 +01:00
XP_UCHAR* name = stringFromStream( MPPARM(globals->mpool)
stream );
dict = ce_dictionary_make( globals, name );
2004-01-17 23:10:23 +01:00
#endif
2003-11-20 17:26:35 +01:00
} else {
dict = NULL;
}
XP_DEBUGF( "calling game_makeFromStream" );
game_makeFromStream( MEMPOOL stream, &globals->game,
&globals->gameInfo,
dict, &globals->util, globals->draw,
&globals->appPrefs.cp, ce_ir_send, globals );
stream_destroy( stream );
}
return success;
} /* ceLoadSavedGame */
#ifndef XWFEATURE_STANDALONE_ONLY
XP_S16
ce_ir_send( XP_U8* buf, XP_U16 len, CommsAddrRec* addr, void* closure )
{
XP_DEBUGF( "ce_ir_send called" );
return -1;
} /* ce_ir_send */
#endif
2004-03-28 03:14:34 +02:00
static void
colorsFromRsrc( CEAppGlobals* globals )
{
XP_U16 i;
HGLOBAL globH;
HRSRC rsrcH;
XP_U16* ptr;
rsrcH = FindResource( globals->hInst, MAKEINTRESOURCE(ID_COLORS_RES),
TEXT("CLRS") );
globH = LoadResource( globals->hInst, rsrcH );
ptr = (XP_U16*)globH;
XP_LOGF( "setting colors in globals" );
for ( i = 0; i < NUM_COLORS; ++i ) {
XP_U8 r = (XP_U8)*ptr++;
XP_U8 g = (XP_U8)*ptr++;
XP_U8 b = (XP_U8)*ptr++;
globals->appPrefs.colors[i] = RGB( r, g, b );
}
DeleteObject( globH );
} /* colorsFromRsrc */
2003-11-20 17:26:35 +01:00
static void
ceInitPrefs( CEAppGlobals* globals )
{
globals->appPrefs.versionFlags = CUR_CE_PREFS_FLAGS;
2004-05-28 04:45:49 +02:00
globals->appPrefs.showColors = XP_TRUE;
2003-11-20 17:26:35 +01:00
globals->appPrefs.cp.showBoardArrow = XP_TRUE;
globals->appPrefs.cp.showRobotScores = XP_FALSE;
2004-03-28 03:14:34 +02:00
colorsFromRsrc( globals );
2003-11-20 17:26:35 +01:00
} /* ceInitPrefs */
//
// FUNCTION: InitInstance(HANDLE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
BOOL
InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // The window class name
CEAppGlobals* globals;
BOOL result = TRUE;
2003-12-09 06:18:47 +01:00
XP_Bool oldGameLoaded;
2003-11-20 17:26:35 +01:00
XP_Bool prevStateExists;
2003-12-09 06:18:47 +01:00
XP_Bool newDone = XP_FALSE;
XP_U16 len;
2003-11-20 17:26:35 +01:00
MPSLOT;
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_XWORDS4, szWindowClass, MAX_LOADSTRING);
//If it is already running, then focus on the window
hWnd = FindWindow( szWindowClass, szTitle);
if ( hWnd ) {
SetForegroundWindow( (HWND)((ULONG) hWnd | 0x00000001) );
return FALSE;
}
(void)CreateDirectory( DEFAULT_DIR_NAME, 0 );
2003-11-20 17:26:35 +01:00
#ifdef MEM_DEBUG
mpool = mpool_make();
#endif
globals = (CEAppGlobals*)XP_MALLOC( mpool, sizeof(*globals) );
XP_DEBUGF( "" );
XP_DEBUGF( "globals created: 0x%lx", globals );
XP_MEMSET( globals, 0, sizeof(*globals) );
MPASSIGN( globals->mpool, mpool );
globals->vtMgr = make_vtablemgr( MPPARM_NOCOMMA(mpool) );
len = wcslen( DEFAULT_DIR_NAME );
len = (len + 1) * sizeof(globals->lastDefaultDir[0]);
globals->lastDefaultDir = XP_MALLOC( mpool, len );
XP_MEMCPY( globals->lastDefaultDir, DEFAULT_DIR_NAME, len );
2003-11-20 17:26:35 +01:00
globals->hInst = hInstance;
// Initialize global strings
MyRegisterClass(hInstance, szWindowClass);
hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, hInstance, globals);
globals->hWnd = hWnd;
if (!hWnd) {
return FALSE;
}
2004-12-17 08:45:30 +01:00
if ( globals->hwndCB ) {
RECT rc, rcmb;
GetWindowRect( hWnd, &rc );
GetWindowRect( globals->hwndCB, &rcmb );
rc.bottom -= (rcmb.bottom - rcmb.top);
MoveWindow(hWnd, rc.left, rc.top, rc.right-rc.left,
rc.bottom-rc.top, FALSE);
}
2003-11-20 17:26:35 +01:00
ceInitUtilFuncs( globals );
/* choose one. If none found it's an error. */
2004-01-17 23:10:23 +01:00
#ifndef STUBBED_DICT
2003-11-20 17:26:35 +01:00
globals->gameInfo.dictName = ceLocateNthDict( MPPARM(mpool) 0 );
result = globals->gameInfo.dictName != NULL;
if ( !result ) {
messageBoxChar( globals, "Please install at least one Crosswords "
"dictionary.", L"Fatal error" );
return FALSE;
}
2004-01-17 23:10:23 +01:00
#endif
gi_initPlayerInfo( MPPARM(mpool) &globals->gameInfo, "Player %d" );
2003-11-20 17:26:35 +01:00
/* here's where we want to behave differently if there's saved state.
But that's a long ways off. */
prevStateExists = ceLoadPrefs( globals );
if ( !prevStateExists ) {
2003-11-20 17:26:35 +01:00
ceInitPrefs( globals );
2004-03-28 03:14:34 +02:00
}
/* must load prefs before creating draw ctxt */
2004-03-28 03:14:34 +02:00
globals->draw = ce_drawctxt_make( MPPARM(globals->mpool)
hWnd, globals );
2003-11-20 17:26:35 +01:00
oldGameLoaded = prevStateExists && ceLoadSavedGame( globals );
2004-03-28 03:14:34 +02:00
if ( !oldGameLoaded ) {
2005-01-21 09:26:32 +01:00
XP_U16 gameID = 0; /* good enough until I get networking going */
2003-11-20 17:26:35 +01:00
game_makeNewGame( MPPARM(mpool) &globals->game, &globals->gameInfo,
2005-01-21 09:26:32 +01:00
&globals->util, globals->draw, gameID,
&globals->appPrefs.cp,
2003-11-20 17:26:35 +01:00
(TransportSend)NULL, globals );
newDone = doNewGame( globals, XP_TRUE ); /* calls ceInitAndStartBoard */
if ( !newDone ) {
result = FALSE;
2003-11-20 17:26:35 +01:00
}
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
if (globals->hwndCB) {
CommandBar_Show(globals->hwndCB, TRUE);
}
2003-12-09 06:18:47 +01:00
if ( result && !newDone ) {
ceInitAndStartBoard( globals, !oldGameLoaded, NULL );
2003-11-20 17:26:35 +01:00
}
return result;
} /* InitInstance */
static XP_Bool
ceHandleHintRequest( CEAppGlobals* globals )
{
XP_Bool notDone;
XP_Bool draw;
XP_ASSERT( !!globals->game.board );
2004-12-11 05:25:45 +01:00
draw = board_requestHint( globals->game.board,
#ifdef XWFEATURE_SEARCHLIMIT
globals->askTrayLimits,
#endif
2004-07-10 19:46:36 +02:00
&notDone );
2003-11-20 17:26:35 +01:00
globals->hintPending = notDone;
return draw;
} /* ceHandleHintRequest */
static XP_Bool
handleTradeCmd( CEAppGlobals* globals )
{
return board_beginTrade( globals->game.board );
} /* handleTradeCmd */
static XP_Bool
handleJuggleCmd( CEAppGlobals* globals )
{
return board_juggleTray( globals->game.board );
} /* handleJuggleCmd */
static XP_Bool
handleHidetrayCmd( CEAppGlobals* globals )
{
XW_TrayVisState curState = board_getTrayVisState( globals->game.board );
if ( curState == TRAY_REVEALED ) {
return board_hideTray( globals->game.board );
} else {
return board_showTray( globals->game.board );
}
} /* handleHidetrayCmd */
static XP_Bool
handleDoneCmd( CEAppGlobals* globals)
{
return board_commitTurn( globals->game.board );
} /* handleDoneCmd */
static void
ceCountsAndValues( CEAppGlobals* globals )
{
if ( !!globals->game.server ) {
XWStreamCtxt* stream = make_generic_stream( globals );
2003-11-20 17:26:35 +01:00
2004-12-18 02:03:26 +01:00
server_formatDictCounts( globals->game.server, stream, 3 );
2003-11-20 17:26:35 +01:00
(void)ceMsgFromStream( globals, stream, L"Tile Counts and Values",
XP_FALSE, XP_TRUE );
2003-11-20 17:26:35 +01:00
}
} /* ceCountsAndValues */
static void
ceTilesLeft( CEAppGlobals* globals )
{
if ( !!globals->game.board ) {
XWStreamCtxt* stream = make_generic_stream( globals );
board_formatRemainingTiles( globals->game.board, stream );
(void)ceMsgFromStream( globals, stream, L"Remaining tiles",
XP_FALSE, XP_TRUE );
}
} /* ceTilesLeft */
2003-11-20 17:26:35 +01:00
static void
ceDoHistory( CEAppGlobals* globals )
{
XP_Bool gameOver = server_getGameIsOver(globals->game.server);
XWStreamCtxt* stream;
stream = make_generic_stream( globals );
2003-11-20 17:26:35 +01:00
model_writeGameHistory( globals->game.model, stream,
globals->game.server, gameOver );
(void)ceMsgFromStream( globals, stream, L"Game history",
XP_FALSE, XP_TRUE );
2003-11-20 17:26:35 +01:00
} /* ceDoHistory */
static void
drawInsidePaint( HWND hWnd, CEAppGlobals* globals )
{
HDC hdc;
hdc = GetDC( hWnd );
if ( !hdc ) {
logLastError( "drawInsidePaint" );
} else {
HDC prevHDC = globals->hdc;
globals->hdc = hdc;
2003-11-20 17:26:35 +01:00
board_draw( globals->game.board );
2003-11-20 17:26:35 +01:00
globals->hdc = prevHDC;
}
2003-11-20 17:26:35 +01:00
} /* drawInsidePaint */
static void
ceDisplayFinalScores( CEAppGlobals* globals )
{
XWStreamCtxt* stream;
stream = make_generic_stream( globals );
2003-11-20 17:26:35 +01:00
server_writeFinalScores( globals->game.server, stream );
stream_putU8( stream, '\0' );
(void)ceMsgFromStream( globals, stream, L"Final scores",
XP_FALSE, XP_TRUE );
2003-11-20 17:26:35 +01:00
} /* ceDisplayFinalScores */
static XP_Bool
doNewGame( CEAppGlobals* globals, XP_Bool silent )
{
GameInfoState giState;
XP_Bool changed = XP_FALSE;
/* What happens if user cancels below? I'm hosed without a name, no?
PENDING */
2003-11-20 17:26:35 +01:00
if ( globals->curGameName != NULL ) {
XP_FREE( globals->mpool, globals->curGameName );
globals->curGameName = NULL;
}
XP_MEMSET( &giState, 0, sizeof(giState) );
giState.globals = globals;
giState.isNewGame = XP_TRUE;
DialogBoxParam( globals->hInst, (LPCTSTR)IDD_GAMEINFO, globals->hWnd,
(DLGPROC)GameInfo, (long)&giState );
2004-01-17 23:10:23 +01:00
if ( !giState.userCancelled
#ifndef STUBBED_DICT
&& ((XP_U16)XP_STRLEN(giState.newDictName) > 0)
#endif
) {
2003-11-20 17:26:35 +01:00
if ( giState.prefsChanged ) {
loadCurPrefsFromState( &globals->appPrefs, &globals->gameInfo,
&giState.prefsPrefs );
if ( giState.colorsChanged ) {
updateForColors( globals );
}
2003-11-20 17:26:35 +01:00
}
ceInitAndStartBoard( globals, XP_TRUE, NULL );
changed = XP_TRUE;
}
return changed;
} /* doNewGame */
static void
ceChooseAndOpen( CEAppGlobals* globals )
{
wchar_t path[256];
OPENFILENAME openFileStruct;
XP_MEMSET( &openFileStruct, 0, sizeof(openFileStruct) );
XP_MEMSET( path, 0, sizeof(path) );
openFileStruct.lStructSize = sizeof(openFileStruct);
openFileStruct.hwndOwner = globals->hWnd;
openFileStruct.lpstrFilter = L"Crosswords games" L"\0"
L"*.xwg" L"\0\0";
openFileStruct.Flags = OFN_FILEMUSTEXIST
| OFN_HIDEREADONLY
| OFN_PATHMUSTEXIST;
openFileStruct.lpstrFile = path;
openFileStruct.nMaxFile = sizeof(path)/sizeof(path[0]);
if ( GetOpenFileName( &openFileStruct ) ) {
XP_UCHAR* name;
XP_U16 len;
len = wcslen(path);
name = XP_MALLOC( globals->mpool, len + 1 );
WideCharToMultiByte( CP_ACP, 0, path, len + 1,
name, len + 1, NULL, NULL );
if ( globals->curGameName != NULL
&& 0 == XP_STRCMP( name, globals->curGameName ) ){ /*already open*/
XP_FREE( globals->mpool, name );
} else if ( ceSaveCurGame( globals, XP_FALSE )
|| queryBoxChar( globals, "Do you really want to "
"overwrite the current game?" ) ) {
2003-11-20 17:26:35 +01:00
if ( globals->curGameName != NULL ) {
XP_FREE( globals->mpool, globals->curGameName );
}
globals->curGameName = name;
ceLoadSavedGame( globals );
ceInitAndStartBoard( globals, XP_FALSE, NULL );
ceSetTitleFromName( globals );
}
}
} /* ceChooseAndOpen */
static void
updateForColors( CEAppGlobals* globals )
{
ce_drawctxt_update( globals->draw, globals );
if ( !!globals->game.board ) {
board_invalAll( globals->game.board );
}
} /* updateForColors */
2003-11-20 17:26:35 +01:00
static void
ceDoPrefsDlg( CEAppGlobals* globals )
{
CePrefsDlgState state;
CePrefsPrefs prefsPrefs;
2003-11-20 17:26:35 +01:00
XP_MEMSET( &state, 0, sizeof(state) );
loadStateFromCurPrefs( &globals->appPrefs, &globals->gameInfo,
&prefsPrefs );
(void)WrapPrefsDialog( globals->hWnd, globals, &state, &prefsPrefs,
XP_FALSE );
if ( !state.userCancelled ) {
loadCurPrefsFromState( &globals->appPrefs, &globals->gameInfo,
&prefsPrefs );
(void)cePositionBoard( globals );
if ( state.colorsChanged ) {
updateForColors( globals );
}
2003-11-20 17:26:35 +01:00
/* need to reflect vars set in state into globals, and update/inval
as appropriate. */
}
} /* ceDoPrefsDlg */
static void
ceWriteToFile( XWStreamCtxt* stream, void* closure )
{
FileWriteState* fwState = (FileWriteState*)closure;
CEAppGlobals* globals = fwState->globals;
XP_UCHAR* path = fwState->path;
wchar_t widebuf[257];
XP_U16 len = (XP_U16)XP_STRLEN( path );
HANDLE fileH;
XP_DEBUGF( "ceWriteToFile called for %s", path );
len = (XP_U16)XP_STRLEN( path );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, path, len + 1,
widebuf, len + 1 );
fileH = CreateFile( widebuf, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if ( fileH != INVALID_HANDLE_VALUE ) {
XP_U16 len = stream_getSize( stream );
XP_UCHAR* buf = XP_MALLOC( globals->mpool, len );
XP_U32 nWritten;
stream_getBytes( stream, buf, len );
WriteFile( fileH, buf, len, &nWritten, NULL );
SetEndOfFile( fileH );
CloseHandle( fileH );
XP_FREE( globals->mpool, buf );
}
} /* ceWriteToFile */
static XP_Bool
isDefaultName( XP_UCHAR* name )
2003-11-20 17:26:35 +01:00
{
return 0 == XP_STRCMP( UNSAVEDGAMEFILENAME, name, );
} /* isDefaultName */
2003-11-20 17:26:35 +01:00
2004-02-18 05:25:29 +01:00
static void
makeUniqueName( wchar_t* buf, XP_U16 bufLen )
{
XP_U16 i;
DWORD attributes;
for ( i = 1; i < 100; ++i ) {
swprintf( buf, DEFAULT_DIR_NAME L"\\Untitled%d.xwg", i );
XP_ASSERT( wcslen(buf) < bufLen );
attributes = GetFileAttributes( buf );
if ( attributes == 0xFFFFFFFF ) {
break;
}
}
/* If we fall out of the loop, the user will be asked to confirm delete
of Untitled99 or somesuch. That's ok.... */
} /* makeUniqueName */
2003-11-20 17:26:35 +01:00
static XP_Bool
ceSaveCurGame( CEAppGlobals* globals, XP_Bool autoSave )
2003-11-20 17:26:35 +01:00
{
XP_Bool confirmed = XP_FALSE;
/* If it doesn't yet have a name, get a path at which to save it. User
has a chance to cancel this. But if there is a name go ahead and save
using it and don't bother giving cancel chance -- since there's no
harm in making 'em restart. Not sure how this changes when IR's
involved. */
XP_UCHAR* name = globals->curGameName;
if ( name == NULL || isDefaultName(name) ) {
2003-11-20 17:26:35 +01:00
wchar_t nameBuf[256];
XP_UCHAR* newName = NULL;
if ( autoSave ) {
XP_U16 len = XP_STRLEN(UNSAVEDGAMEFILENAME) + 1;
newName = XP_MALLOC( globals->mpool, len );
XP_MEMCPY( newName, UNSAVEDGAMEFILENAME, len );
confirmed = XP_TRUE;
} else {
2003-11-20 17:26:35 +01:00
OPENFILENAME sfs;
2003-11-20 17:26:35 +01:00
XP_MEMSET( &sfs, 0, sizeof(sfs) );
XP_MEMSET( nameBuf, 0, sizeof(nameBuf) );
2003-11-20 17:26:35 +01:00
2004-02-18 05:25:29 +01:00
makeUniqueName( nameBuf, sizeof(nameBuf)/sizeof(nameBuf[0]) );
sfs.lStructSize = sizeof(sfs);
sfs.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
sfs.hwndOwner = globals->hWnd;
sfs.lpstrFile = nameBuf;
sfs.nMaxFile = sizeof(nameBuf)/sizeof(nameBuf[0]);
sfs.lpstrDefExt = L"xwg";
// sfs.lpstrTitle: doesn't work
// sfs.lpstrInitialDir: doesn't either
confirmed = GetSaveFileName( &sfs );
if ( confirmed ) {
XP_U16 len = wcslen(nameBuf);
XP_DEBUGF( "len(nameBuf) = %d", len );
newName = XP_MALLOC( globals->mpool, len + 1 );
WideCharToMultiByte( CP_ACP, 0, nameBuf, len + 1,
newName, len + 1, NULL, NULL );
/* If user picked from a different directory, remember it
as the new starting point. */
nameBuf[sfs.nFileOffset] = 0;
if ( wcscmp( nameBuf, globals->lastDefaultDir ) != 0 ) {
XP_FREE( globals->mpool, globals->lastDefaultDir );
globals->lastDefaultDir =
XP_MALLOC( globals->mpool,
(sfs.nFileOffset + 1) * 2 );
wcscpy( globals->lastDefaultDir, nameBuf );
}
}
}
2003-11-20 17:26:35 +01:00
if ( confirmed ) {
XP_ASSERT( !!newName );
if ( !!globals->curGameName ) {
XP_FREE( globals->mpool, globals->curGameName );
}
globals->curGameName = newName;
2003-11-20 17:26:35 +01:00
}
} else {
confirmed = XP_TRUE;
}
if ( confirmed ) {
if ( !!globals->game.server ) {
XWStreamCtxt* memStream;
DictionaryCtxt* dict;
FileWriteState fwState;
char* dictName;
fwState.path = globals->curGameName;
fwState.globals = globals;
#ifndef CE_DEBUG_SAVEOFTEN
2003-11-20 17:26:35 +01:00
board_hideTray( globals->game.board ); /* so won't be visible when
next opened */
#endif
2003-11-20 17:26:35 +01:00
memStream = mem_stream_make( MEMPOOL globals->vtMgr, &fwState, 0,
ceWriteToFile );
stream_open( memStream );
ceSaveGamePrefs( globals, memStream );
/* the dictionary */
dict = model_getDictionary( globals->game.model );
#ifdef STUBBED_DICT /* don't check this in!!! */
dictName = NULL;
#else
2003-11-20 17:26:35 +01:00
dictName = !!dict? dict_getName( dict ) : NULL;
#endif
2003-11-20 17:26:35 +01:00
stream_putU8( memStream, (XP_U8)!!dictName );
if ( !!dictName ) {
stringToStream( memStream, dictName );
}
game_saveToStream( &globals->game, &globals->gameInfo, memStream );
stream_destroy( memStream );
}
}
return confirmed;
} /* ceSaveCurGame */
static XP_Bool
ceConfirmAndSave( CEAppGlobals* globals )
{
XP_Bool confirmed = ceSaveCurGame( globals, XP_TRUE );
2003-11-20 17:26:35 +01:00
if ( confirmed ) {
ceSavePrefs( globals );
}
return confirmed;
} /* ceConfirmAndSave */
2004-12-17 08:45:30 +01:00
static HWND
makeCommandBar( HWND hwnd, HINSTANCE hInst )
{
SHMENUBARINFO mbi;
XP_MEMSET( &mbi, 0, sizeof(SHMENUBARINFO) );
mbi.cbSize = sizeof(SHMENUBARINFO);
mbi.hwndParent = hwnd;
mbi.nToolBarId = IDM_MENU;
mbi.hInstRes = hInst;
//mbi.dwFlags = SHCMBF_HIDESIPBUTTON; /* eeh added. Why??? */
2004-12-17 08:45:30 +01:00
if (!SHCreateMenuBar(&mbi)) {
XP_LOGF( "SHCreateMenuBar failed" );
return NULL;
}
return mbi.hwndMB;
} /* makeCommandBar */
#ifdef CEFEATURE_CANSCROLL
static XP_Bool
handleScroll( CEAppGlobals* globals, XP_S16 pos, /* only valid for THUMB* */
XP_S16 code, HWND wnd )
{
XP_Bool result = XP_FALSE;
if ( wnd == globals->scrollHandle ) {
XP_S16 newOffset;
XP_U16 curYOffset = board_getYOffset( globals->game.board );
XP_ASSERT( !!globals->game.board );
switch ( code ) {
/* case SB_BOTTOM: // Scrolls to the lower right */
/* case SB_ENDSCROLL: // Ends scroll */
case SB_LINEUP: // Scrolls one line up
case SB_PAGEUP: //
newOffset = curYOffset - 1;
break;
case SB_LINEDOWN: // Scrolls one line down
case SB_PAGEDOWN: // Scrolls one page down
newOffset = curYOffset + 1;
break;
case SB_THUMBTRACK: /* still dragging; don't redraw */
case SB_THUMBPOSITION:
XP_LOGF( "Got scroll message: %d", pos );
newOffset = pos;
break;
default:
newOffset = -1;
/* do nothing */
}
if ( newOffset >= 0 && newOffset <= globals->nHiddenRows ) {
result = curYOffset != newOffset;
if ( result ) {
result = board_setYOffset( globals->game.board, newOffset );
}
}
}
return result;
} /* handleScroll */
#endif
#ifdef CE_DEBUG_SAVEOFTEN
static void
debug_saveCurState( CEAppGlobals* globals )
{
ceSaveCurGame( globals, XP_TRUE );
ceSavePrefs( globals );
}
#else
# define debug_saveCurState(g)
#endif
2003-11-20 17:26:35 +01:00
LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
RECT rt;
XP_Bool draw = XP_FALSE;
XWTimerReason why;
CEAppGlobals* globals;
XP_Bool handled;
2003-11-20 17:26:35 +01:00
if ( message == WM_CREATE ) {
globals = ((CREATESTRUCT*)lParam)->lpCreateParams;
SetWindowLong( hWnd, GWL_USERDATA, (long)globals );
2004-12-17 08:45:30 +01:00
globals->hwndCB = makeCommandBar( hWnd, globals->hInst );
2003-11-20 17:26:35 +01:00
addButtonsToCmdBar( globals );
globals->sai.cbSize = sizeof(globals->sai);
2003-11-20 17:26:35 +01:00
} else {
globals = (CEAppGlobals*)GetWindowLong( hWnd, GWL_USERDATA );
switch (message) {
2004-12-17 08:45:30 +01:00
case WM_ACTIVATE:
// Notify shell of our activate message
SHHandleWMActivate( hWnd, wParam, lParam, &globals->sai, FALSE );
break;
case WM_SETTINGCHANGE:
SHHandleWMSettingChange( hWnd, wParam, lParam, &globals->sai );
cePositionBoard( globals );
board_invalAll( globals->game.board );
draw = XP_TRUE;
2004-12-17 08:45:30 +01:00
break;
#ifdef CEFEATURE_CANSCROLL
case WM_VSCROLL:
draw = handleScroll( globals, (short int)HIWORD(wParam),
(short int)LOWORD(wParam),
(HWND)lParam );
break;
#endif
2003-11-20 17:26:35 +01:00
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId) {
case ID_FILE_ABOUT:
DialogBox(globals->hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd,
(DLGPROC)About);
break;
case ID_GAME_GAMEINFO: {
GameInfoState state;
XP_MEMSET( &state, 0, sizeof(state) );
state.globals = globals;
state.isNewGame = XP_FALSE;
DialogBoxParam(globals->hInst, (LPCTSTR)IDD_GAMEINFO, hWnd,
(DLGPROC)GameInfo, (long)&state );
if ( !state.userCancelled && state.prefsChanged ) {
/* need to update some prefs? */
/* if ( state.colorsChanged ) { */
updateForColors( globals );
/* } */
2003-11-20 17:26:35 +01:00
}
}
2003-11-20 17:26:35 +01:00
break;
case ID_FILE_NEWGAME:
XP_LOGF( "ID_FILE_NEWGAME" );
if ( ceSaveCurGame( globals, XP_FALSE )
|| queryBoxChar( globals, "Do you really want to "
"overwrite the current game?" ) ) {
draw = doNewGame( globals, XP_FALSE );
}
2003-11-20 17:26:35 +01:00
break;
case ID_FILE_SAVEDGAMES:
ceChooseAndOpen( globals );
break;
case ID_FILE_PREFERENCES:
ceDoPrefsDlg( globals );
break;
case ID_GAME_FINALSCORES:
if ( server_getGameIsOver( globals->game.server ) ) {
ceDisplayFinalScores( globals );
} else if ( queryBoxChar( globals,
"Are you sure you want to end "
"the game now?" ) ) {
server_endGame( globals->game.server );
draw = TRUE;
}
break;
case ID_GAME_TILECOUNTSANDVALUES:
ceCountsAndValues( globals );
break;
case ID_GAME_TILESLEFT:
ceTilesLeft( globals );
break;
2003-11-20 17:26:35 +01:00
case ID_GAME_HISTORY:
ceDoHistory( globals );
break;
case ID_MOVE_TRADE:
draw = handleTradeCmd( globals );
break;
case ID_MOVE_JUGGLE:
case JUGGLE_BUTTON_ID:
2003-11-20 17:26:35 +01:00
draw = handleJuggleCmd( globals );
break;
case ID_MOVE_HIDETRAY:
draw = handleHidetrayCmd( globals );
break;
case ID_MOVE_TURNDONE:
draw = handleDoneCmd( globals);
break;
case FLIP_BUTTON_ID:
draw = board_flip( globals->game.board );
break;
case VALUE_BUTTON_ID:
draw = board_toggle_showValues( globals->game.board );
break;
case ID_MOVE_HINT:
2004-07-10 19:46:36 +02:00
#ifdef XWFEATURE_SEARCHLIMIT
case ID_MOVE_LIMITEDHINT:
globals->askTrayLimits = wmId == ID_MOVE_LIMITEDHINT;
#endif
2003-11-20 17:26:35 +01:00
board_resetEngine( globals->game.board );
2004-07-10 19:46:36 +02:00
/* fallthru */
2003-11-20 17:26:35 +01:00
case ID_MOVE_NEXTHINT:
case HINT_BUTTON_ID:
draw = ceHandleHintRequest( globals );
break;
case IDM_FILE_EXIT:
if ( ceConfirmAndSave( globals ) ) { /* user may cancel... */
DestroyWindow(hWnd);
}
break;
case ID_MOVE_UNDOCURRENT:
draw = board_replaceTiles( globals->game.board );
break;
case ID_MOVE_UNDOLAST:
draw = server_handleUndo( globals->game.server );
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
if ( !!globals && GetUpdateRect( hWnd, &rt, FALSE ) ) {
XP_Rect rect;
if ( !!globals->game.board ) {
/* When an obscuring window goes away, the update region
needs to be redrawn. This allows invalidating it. */
RECTtoXPR( &rect, &rt );
board_invalRect( globals->game.board, &rect );
drawInsidePaint( hWnd, globals );
}
if ( !ValidateRect( hWnd, &rt ) ) {
logLastError( "WM_PAINT:ValidateRect" );
}
2003-11-20 17:26:35 +01:00
}
break;
case WM_LBUTTONDOWN:
globals->penDown = XP_TRUE;
draw = board_handlePenDown( globals->game.board, LOWORD(lParam),
HIWORD(lParam), 0, &handled );
debug_saveCurState( globals );
2003-11-20 17:26:35 +01:00
break;
case WM_MOUSEMOVE:
if ( globals->penDown ) {
draw = board_handlePenMove( globals->game.board,
LOWORD(lParam),
HIWORD(lParam) );
debug_saveCurState( globals );
2003-11-20 17:26:35 +01:00
}
break;
case WM_LBUTTONUP:
if ( globals->penDown ) {
draw = board_handlePenUp( globals->game.board, LOWORD(lParam),
HIWORD(lParam), 0 );
globals->penDown = XP_FALSE;
debug_saveCurState( globals );
2003-11-20 17:26:35 +01:00
}
break;
case WM_CHAR:
if ( wParam == 0x08 ) {
wParam = XP_CURSOR_KEY_DEL;
}
draw = board_handleKey( globals->game.board, wParam )
|| board_handleKey( globals->game.board, wParam - ('a'-'A') );
debug_saveCurState( globals );
2003-11-20 17:26:35 +01:00
break;
case WM_TIMER:
why = (XWTimerReason)wParam;
if ( why == TIMER_PENDOWN || why == TIMER_TIMERTICK ) {
board_timerFired( globals->game.board, why );
2004-06-16 06:16:22 +02:00
/* they otherwise repeat.... */
XP_ASSERT( why <= N_TIMER_TYPES );
(void)KillTimer( hWnd, globals->timerIDs[why-1] );
2003-11-20 17:26:35 +01:00
}
break;
case WM_DESTROY:
CommandBar_Destroy(globals->hwndCB); /* supposedly not needed */
2003-11-20 17:26:35 +01:00
PostQuitMessage(0);
break;
case XWWM_TIME_RQST:
draw = server_do( globals->game.server );
2003-11-20 17:26:35 +01:00
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
if ( draw ) {
/* This is stupid. We can't just say "draw" because windoze clips
drawing to the inval rect, and the board isn't set up to tell us
what its inval rect is. So we inval everything, and then when the
WM_PAINT message comes we inval the whole board because there's a
huge inval rect. Dumb. Need to figure out how to have the
methods in cedraw.c set the clip region to encompass the object
being drawn -- taking board's word for it -- or the intersection
of that with the actual clip rgn in the case where some window's
gone away and revealed a large rect board didn't know about. That
was the source of some trouble on Palm, and CE's so fast this
works. But it's stupid. */
RECT r = { 100, 100, 102, 102 };
InvalidateRect( globals->hWnd, &r, FALSE /* erase */ );
2003-11-20 17:26:35 +01:00
}
return 0;
} /* WndProc */
// Mesage handler for the About box.
LRESULT CALLBACK
About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
} /* About */
static void
notImpl( CEAppGlobals* globals )
{
messageBoxChar( globals, "feature not implemented", NULL );
} /* notImpl */
static XP_Bool
2003-11-20 17:26:35 +01:00
ceMsgFromStream( CEAppGlobals* globals, XWStreamCtxt* stream,
wchar_t* title, XP_Bool isQuery, XP_Bool destroy )
2003-11-20 17:26:35 +01:00
{
StrBoxInit init;
init.title = title;
init.stream = stream;
init.isQuery = isQuery;
2003-11-20 17:26:35 +01:00
init.globals = globals;
DialogBoxParam( globals->hInst, (LPCTSTR)IDD_STRBOX, globals->hWnd,
(DLGPROC)StrBox, (long)&init );
if ( destroy ) {
stream_destroy( stream );
}
return init.result == IDOK;
2003-11-20 17:26:35 +01:00
} /* ceMsgFromStream */
static void
messageBoxChar( CEAppGlobals* globals, XP_UCHAR* str, wchar_t* title )
{
wchar_t* widebuf;
XP_U32 len, wsize;
/* first get the length required, then alloc and go */
len = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, str, strlen(str),
NULL, 0 );
wsize = (len+1) * sizeof( wchar_t );
widebuf = XP_MALLOC( globals->mpool, wsize );
XP_MEMSET( widebuf, 0, wsize );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, str, strlen(str),
widebuf, len );
MessageBox( globals->hWnd, widebuf, title, MB_OK );
XP_FREE( globals->mpool, widebuf );
} /* messageBoxChar */
static XP_UCHAR*
ceStreamToStrBuf( MPFORMAL XWStreamCtxt* stream )
{
XP_U16 len = stream_getSize( stream );
XP_UCHAR* buf = XP_MALLOC( mpool, len + 1 );
stream_getBytes( stream, buf, len );
buf[len] = '\0';
return buf;
} /* ceStreamToStrBuf */
static void
messageBoxStream( CEAppGlobals* globals, XWStreamCtxt* stream, wchar_t* title )
{
XP_UCHAR* buf = ceStreamToStrBuf( MPPARM(globals->mpool) stream );
messageBoxChar( globals, buf, title );
XP_FREE( globals->mpool, buf );
} /* messageBoxStream */
static XP_Bool
queryBoxChar( CEAppGlobals* globals, XP_UCHAR* msg )
{
wchar_t widebuf[128];
XP_U16 answer;
XP_U16 len = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, msg, strlen(msg),
widebuf,
sizeof(widebuf)/sizeof(widebuf[0]) );
widebuf[len] = 0;
answer = MessageBox( globals->hWnd, widebuf, L"Question", MB_YESNO );
return answer == IDOK || answer == IDYES;
} /* queryBoxChar */
static XP_Bool
queryBoxStream( CEAppGlobals* globals, XWStreamCtxt* stream )
{
XP_UCHAR* buf = ceStreamToStrBuf( MPPARM(globals->mpool) stream );
XP_Bool result = queryBoxChar( globals, buf );
XP_FREE( globals->mpool, buf );
return result;
} /* queryBoxStream */
static XP_Bool
ceQueryFromStream( CEAppGlobals* globals, XWStreamCtxt* stream )
{
return ceMsgFromStream( globals, stream, L"Question", XP_TRUE,
XP_FALSE );
} /* ceQueryFromStream */
2003-11-20 17:26:35 +01:00
static void
RECTtoXPR( XP_Rect* dest, RECT* src )
{
dest->top = (short)src->top;
dest->left = (short)src->left;
dest->width = (short)(src->right - src->left);
dest->height = (short)(src->bottom - src->top);
} /* RECTtoXPR */
void
wince_assert( XP_UCHAR* s, int line, char* fileName )
{
XP_WARNF( "ASSERTION FAILED %s: file %s, line %d\n", s, fileName, line );
} /* wince_assert */
static void
makeTimeStamp( XP_UCHAR* timeStamp, XP_U16 size )
{
SYSTEMTIME st;
GetLocalTime( &st );
sprintf( timeStamp, "%d:%.2d:%.2d ", st.wHour, st.wMinute, st.wSecond );
XP_ASSERT( size > strlen(timeStamp) );
} /* makeTimeStamp */
void
wince_debugf(XP_UCHAR* format, ...)
{
XP_UCHAR buf[256];
/* wchar_t widebuf[256]; */
va_list ap;
va_start( ap, format );
vsprintf( buf, format, ap );
va_end(ap);
#if 0
messageBoxChar( globals, buf, NULL );
/* #elif defined _WIN32_WCE_EMULATION */
/* XP_MEMSET( widebuf, 0, sizeof(widebuf) ); */
/* MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, buf, strlen(buf), */
/* widebuf, sizeof(widebuf)/sizeof(widebuf[0]) ); */
/* OutputDebugString( widebuf ); */
#else
{
/* Create logfile if necessary and write to it in ascii. */
XP_U16 nBytes;
XP_U32 nWritten;
HANDLE fileH;
XP_UCHAR timeStamp[32];
makeTimeStamp(timeStamp, sizeof(timeStamp));
fileH = CreateFile( L"\\My Documents\\Crosswords\\xwDbgLog.txt",
GENERIC_WRITE, 0, NULL,
2003-11-20 17:26:35 +01:00
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
#ifdef _WIN32_WCE_EMULATION
strcat( buf, "\n" );
#else
strcat( buf, XP_CR );
#endif
SetFilePointer( fileH, 0, 0, FILE_END );
nBytes = strlen( timeStamp );
WriteFile( fileH, timeStamp, nBytes, &nWritten, NULL );
XP_ASSERT( nWritten == nBytes );
nBytes = strlen( buf );
WriteFile( fileH, buf, nBytes, &nWritten, NULL );
XP_ASSERT( nWritten == nBytes );
CloseHandle( fileH );
}
#endif
} /* wince_debugf */
XP_U16
wince_snprintf( XP_UCHAR* buf, XP_U16 len, XP_UCHAR* format, ... )
{
va_list ap;
va_start( ap, format );
2004-12-18 02:03:26 +01:00
_vsnprintf( buf, len, format, ap );
2003-11-20 17:26:35 +01:00
/* FormatMessage( */
/* FORMAT_MESSAGE_FROM_STRING, */
/* format, */
/* 0, */
/* 0, // Default language */
/* (LPTSTR)buf, */
/* len, &ap ); */
va_end(ap);
return strlen(buf);
} /* wince_snprintf */
/* I can't believe the stupid compiler's making me implement this */
void p_ignore(XP_UCHAR* c, ...){}
static VTableMgr*
ce_util_getVTManager( XW_UtilCtxt* uc )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
return globals->vtMgr;
} /* ce_util_getVTManager */
static void
ce_util_userError( XW_UtilCtxt* uc, UtilErrID id )
{
XP_UCHAR* message;
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
switch( id ) {
case ERR_TILES_NOT_IN_LINE:
message = "All tiles played must be in a line.";
break;
case ERR_NO_EMPTIES_IN_TURN:
message = "Empty squares cannot separate tiles played.";
break;
case ERR_TWO_TILES_FIRST_MOVE:
message = "Must play two or more pieces on the first move.";
break;
case ERR_TILES_MUST_CONTACT:
message = "New pieces must contact others already in place (or "
"the middle square on the first move).";
break;
case ERR_NOT_YOUR_TURN:
message = "You can't do that; it's not your turn!";
break;
case ERR_NO_PEEK_ROBOT_TILES:
message = "No peeking at the robot's tiles!";
break;
case ERR_CANT_TRADE_MID_MOVE:
message = "Remove played tiles before trading.";
break;
case ERR_TOO_FEW_TILES_LEFT_TO_TRADE:
message = "Too few tiles left to trade.";
break;
2004-05-15 03:07:34 +02:00
case ERR_CANT_UNDO_TILEASSIGN:
message = "Tile assignment can't be undone.";
break;
2003-11-20 17:26:35 +01:00
default:
message = "unknown errorcode ID!!!";
break;
}
messageBoxChar( globals, message, L"Oops!" );
} /* ce_util_userError */
static XP_Bool
2003-11-20 17:26:35 +01:00
ce_util_userQuery( XW_UtilCtxt* uc, UtilQueryID id, XWStreamCtxt* stream )
{
char* query = NULL;
char* info = NULL;
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
XP_Bool answer = XP_FALSE;
2003-11-20 17:26:35 +01:00
XP_Bool queryWithStream = XP_FALSE;
switch( id ) {
case QUERY_COMMIT_TURN:
return ceQueryFromStream( globals, stream );
2003-11-20 17:26:35 +01:00
case QUERY_COMMIT_TRADE:
query = "Are you sure you want to spend this move trading tiles?";
return queryBoxChar( globals, query );
2003-11-20 17:26:35 +01:00
case QUERY_ROBOT_MOVE:
return ceMsgFromStream( globals, stream, L"FYI", XP_FALSE,
XP_FALSE );
case QUERY_ROBOT_TRADE:
messageBoxStream( globals, stream, L"FYI" );
2003-11-20 17:26:35 +01:00
break;
default:
XP_ASSERT(0);
}
return XP_FALSE;
2003-11-20 17:26:35 +01:00
} /* ce_util_userQuery */
static XWBonusType
ce_util_getSquareBonus( XW_UtilCtxt* uc, ModelCtxt* model,
XP_U16 col, XP_U16 row )
{
XP_U16 index;
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
if ( !globals->bonusInfo ) {
HRSRC rsrcH;
HGLOBAL globH;
rsrcH = FindResource( globals->hInst, MAKEINTRESOURCE(ID_BONUS_RES),
TEXT("BONS") );
if ( !!rsrcH ) {
globH = LoadResource( globals->hInst, rsrcH );
if ( !!globH ) {
globals->bonusInfo = (XP_U16*)globH;
/* We don't want to call DeleteObject here, but should when
the app closes. Or does Wince free up all memory
associated with a process when it closes? PENDING(eeh) */
// DeleteObject( globH );
}
}
}
2003-11-20 17:26:35 +01:00
if ( col > 7 ) col = 14 - col;
if ( row > 7 ) row = 14 - row;
index = (row*8) + col;
if ( !globals->bonusInfo || (index >= 8*8) ) {
XP_ASSERT( 0 );
return (XWBonusType)BONUS_NONE;
2003-11-20 17:26:35 +01:00
} else {
/* This is probably a bit slow. Consider caching the resource in
memory with one bonus value per byte. */
XP_U16 value = globals->bonusInfo[index/4];
value >>= ((3 - (index % 4)) * 4);
return value & 0x0F;
2003-11-20 17:26:35 +01:00
}
} /* ce_util_getSquareBonus */
static XP_S16
ce_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi,
2003-11-20 17:26:35 +01:00
XP_U16 playerNum,
const XP_UCHAR4* texts, XP_U16 nTiles )
2003-11-20 17:26:35 +01:00
{
BlankDialogState state;
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
XP_MEMSET( &state, 0, sizeof(state) );
2003-12-09 06:18:47 +01:00
state.globals = globals;
2003-11-20 17:26:35 +01:00
state.texts = texts;
state.nTiles = nTiles;
state.playerNum = playerNum;
state.pi = pi;
DialogBoxParam( globals->hInst, (LPCTSTR)IDD_ASKBLANK, globals->hWnd,
(DLGPROC)BlankDlg, (long)&state );
return state.result;
} /* ce_util_userPickTile */
static XP_Bool
ce_util_askPassword( XW_UtilCtxt* uc, const XP_UCHAR* name,
XP_UCHAR* buf, XP_U16* len )
{
PasswdDialogState state;
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
XP_MEMSET( &state, 0, sizeof(state) );
state.name = name;
state.buf = buf;
state.lenp = len;
DialogBoxParam( globals->hInst, (LPCTSTR)IDD_ASKPASS, globals->hWnd,
(DLGPROC)PasswdDlg, (long)&state );
return !state.userCancelled;
} /* ce_util_askPassword */
static void
ce_util_trayHiddenChange( XW_UtilCtxt* uc, XP_Bool nowHidden )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
#ifdef CEFEATURE_CANSCROLL
/* If there's a scrollbar, hide/show it. It wants to be
active/visible only when the tray is NOT hidden */
if ( !!globals->scrollHandle ) {
EnableWindow( globals->scrollHandle, nowHidden );
}
#endif
drawInsidePaint( globals->hWnd, globals );
2003-11-20 17:26:35 +01:00
} /* ce_util_trayHiddenChange */
static void
ce_util_yOffsetChange( XW_UtilCtxt* uc, XP_U16 oldOffset,
XP_U16 newOffset )
{
#ifdef CEFEATURE_CANSCROLL
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
(void)SetScrollPos( globals->scrollHandle, SB_CTL, newOffset, XP_TRUE );
#endif
2003-11-20 17:26:35 +01:00
} /* ce_util_yOffsetChange */
static void
ce_util_notifyGameOver( XW_UtilCtxt* uc )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
drawInsidePaint( globals->hWnd, globals );
ceDisplayFinalScores( globals );
} /* ce_util_notifyGameOver */
static XP_Bool
ce_util_hiliteCell( XW_UtilCtxt* uc, XP_U16 col, XP_U16 row )
{
return XP_TRUE;
} /* ce_util_hiliteCell */
static XP_Bool
ce_util_engineProgressCallback( XW_UtilCtxt* uc )
{
return XP_TRUE;
} /* ce_util_engineProgressCallback */
static void
ce_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
2004-06-16 06:16:22 +02:00
XP_U32 timerID;
XP_U32 howLong;
2003-11-20 17:26:35 +01:00
if ( why == TIMER_PENDOWN ) {
howLong = 400;
2003-11-20 17:26:35 +01:00
} else if ( why == TIMER_TIMERTICK ) {
howLong = 1000; /* 1 second */
2004-06-16 06:16:22 +02:00
} else {
XP_ASSERT(0);
return;
2003-11-20 17:26:35 +01:00
}
timerID = SetTimer( globals->hWnd, why, howLong, NULL);
2004-06-16 06:16:22 +02:00
XP_ASSERT( why <= N_TIMER_TYPES );
globals->timerIDs[why-1] = timerID;
2003-11-20 17:26:35 +01:00
} /* ce_util_setTimer */
static void
ce_util_requestTime( XW_UtilCtxt* uc )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
PostMessage( globals->hWnd, XWWM_TIME_RQST, 0, 0 );
} /* palm_util_requestTime */
static XP_U32
ce_util_getCurSeconds( XW_UtilCtxt* uc )
{
return 0L;
} /* ce_util_getCurSeconds */
static DictionaryCtxt*
ce_util_makeEmptyDict( XW_UtilCtxt* uc )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
2004-01-17 23:10:23 +01:00
#ifdef STUBBED_DICT
return make_stubbed_dict( MPPARM_NOCOMMA(globals->mpool) );
#else
2003-11-20 17:26:35 +01:00
return ce_dictionary_make( globals, NULL );
2004-01-17 23:10:23 +01:00
#endif
2003-11-20 17:26:35 +01:00
} /* ce_util_makeEmptyDict */
#ifndef XWFEATURE_STANDALONE_ONLY
static XWStreamCtxt*
ce_util_makeStreamFromAddr( XW_UtilCtxt* uc, XP_U16 channelNo )
{
} /* ce_util_makeStreamFromAddr */
#endif
static XP_UCHAR*
ce_util_getUserString( XW_UtilCtxt* uc, XP_U16 stringCode )
{
switch( stringCode ) {
case STRD_REMAINING_TILES_ADD:
return (XP_UCHAR*)"+ %d [all remaining tiles]";
case STRD_UNUSED_TILES_SUB:
return (XP_UCHAR*)"- %d [unused tiles]";
case STR_BONUS_ALL:
return (XP_UCHAR*)"Bonus for using all tiles: 50" XP_CR;
case STRD_TURN_SCORE:
return (XP_UCHAR*)"Score for turn: %d" XP_CR;
case STR_COMMIT_CONFIRM:
return (XP_UCHAR*)"Commit the current move?" XP_CR;
2004-05-01 16:30:34 +02:00
case STR_LOCAL_NAME:
return (XP_UCHAR*)"%s";
2003-11-20 17:26:35 +01:00
case STR_NONLOCAL_NAME:
return (XP_UCHAR*)"%s (remote)";
case STRD_TIME_PENALTY_SUB:
return (XP_UCHAR*)" - %d [time]";
case STRD_CUMULATIVE_SCORE:
return (XP_UCHAR*)"Cumulative score: %d" XP_CR;
case STRS_MOVE_ACROSS:
return (XP_UCHAR*)"move (from %s across)" XP_CR;
case STRS_MOVE_DOWN:
return (XP_UCHAR*)"move (from %s down)" XP_CR;
case STRS_TRAY_AT_START:
return (XP_UCHAR*)"Tray at start: %s" XP_CR;
case STRS_NEW_TILES:
return (XP_UCHAR*)"New tiles: %s" XP_CR;
case STRSS_TRADED_FOR:
return (XP_UCHAR*)"Traded %s for %s.";
case STR_PASS:
return (XP_UCHAR*)"pass" XP_CR;
case STR_PHONY_REJECTED:
return (XP_UCHAR*)"Illegal word in move; turn lost!" XP_CR;
case STRD_ROBOT_TRADED:
return (XP_UCHAR*)"Robot traded tiles %d this turn.";
case STR_ROBOT_MOVED:
return (XP_UCHAR*)"The robot made this move:" XP_CR;
case STR_REMOTE_MOVED:
return (XP_UCHAR*)"Remote player made this move:" XP_CR;
2004-05-13 04:13:48 +02:00
case STR_PASSED:
return (XP_UCHAR*)"Passed";
case STRSD_SUMMARYSCORED:
return (XP_UCHAR*)"%s:%d";
case STRD_TRADED:
return (XP_UCHAR*)"Traded %d";
case STR_LOSTTURN:
return (XP_UCHAR*)"Lost turn";
case STRS_VALUES_HEADER:
return (XP_UCHAR*)"%s counts/values:" XP_CR;
2003-11-20 17:26:35 +01:00
default:
2004-05-01 16:30:34 +02:00
XP_LOGF( "stringCode=%d", stringCode );
2003-11-20 17:26:35 +01:00
return (XP_UCHAR*)"unknown code";
}
} /* ce_util_getUserString */
static void
ce_formatBadWords( BadWordInfo* bwi, XP_UCHAR buf[], XP_U16 bufsiz )
2003-11-20 17:26:35 +01:00
{
XP_U16 i;
for ( i = 0, buf[0] = '\0'; ; ) {
XP_UCHAR wordBuf[18];
sprintf( wordBuf, "\"%s\"", bwi->words[i] );
XP_ASSERT( strlen(wordBuf) < sizeof(wordBuf)-1 );
strncat( buf, wordBuf, bufsiz - 1 );
2003-11-20 17:26:35 +01:00
if ( ++i == bwi->nWords ) {
break;
}
bufsiz -= strlen( wordBuf );
strncat( buf, ", ", bufsiz - 1 );
bufsiz -= 2;
2003-11-20 17:26:35 +01:00
}
} /* ce_formatBadWords */
static XP_Bool
ce_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi,
XP_U16 turn, XP_Bool turnLost )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
XP_UCHAR wordsBuf[256];
XP_UCHAR msgBuf[256];
XP_Bool isOk;
ce_formatBadWords( bwi, wordsBuf, sizeof(wordsBuf) );
2003-11-20 17:26:35 +01:00
sprintf( msgBuf, "Word[s] %s not found in dictionary.", wordsBuf );
if ( turnLost ) {
messageBoxChar( globals, msgBuf, L"Illegal word" );
isOk = XP_TRUE;
} else {
strcat( msgBuf, " Use it anyway?" );
isOk = queryBoxChar( globals, msgBuf );
}
return isOk;
} /* ce_util_warnIllegalWord */
2004-07-10 19:46:36 +02:00
#ifdef XWFEATURE_SEARCHLIMIT
static XP_Bool
ce_util_getTraySearchLimits( XW_UtilCtxt* uc, XP_U16* min, XP_U16* max )
{
CEAppGlobals* globals = (CEAppGlobals*)uc->closure;
HintLimitsState hls;
XP_MEMSET( &hls, 0, sizeof(hls) );
hls.globals = globals;
hls.min = *min;
hls.max = *max;
DialogBoxParam( globals->hInst, (LPCTSTR)IDD_ASKHINTLIMTS, globals->hWnd,
(DLGPROC)HintLimitsDlg, (long)&hls );
if ( !hls.cancelled ) {
*min = hls.min;
*max = hls.max;
}
return !hls.cancelled;
} /* ce_util_getTraySearchLimits */
#endif
2003-11-20 17:26:35 +01:00
#ifdef SHOW_PROGRESS
static void
ce_util_engineStarting( XW_UtilCtxt* uc )
{
} /* ce_util_engineStarting */
static void
ce_util_engineStopping( XW_UtilCtxt* uc )
{
} /* ce_util_engineStopping */
#endif