xwords/xwords4/wince/ceginfo.c

553 lines
18 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-2006 by Eric House (xwords@eehouse.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.
*/
#include <stdio.h> /* swprintf */
2003-11-20 17:26:35 +01:00
#include "ceginfo.h"
#include "cemain.h"
#include "ceutil.h"
#include "cedict.h"
#include "cecondlg.h"
2003-11-20 17:26:35 +01:00
#include "strutils.h"
#define NUM_COLS 4
#define MENUDICTS_INCR 16
2003-11-20 17:26:35 +01:00
static XP_S16
findInsertPoint( const wchar_t* wPath, wchar_t** menuDicts,
XP_U16 nMenuDicts )
{
XP_S16 loc = 0; /* simple case: nothing here */
if ( nMenuDicts > 0 ) {
wchar_t thisShortBuf[CE_MAX_PATH_LEN+1];
wchar_t* thisShortName = wbname( thisShortBuf, sizeof(thisShortBuf),
wPath );
/* If the short path doesn't already exist, find where it belongs. This
is wasteful if we're doing this a lot since the short path isn't
cached. */
for ( /* loc = 0*/; loc < nMenuDicts; ++loc ) {
wchar_t oneShortBuf[CE_MAX_PATH_LEN+1];
wchar_t* oneShortName = wbname( oneShortBuf, sizeof(oneShortBuf),
menuDicts[loc] );
int diff = _wcsicmp( thisShortName, oneShortName );
if ( diff > 0 ) {
continue;
} else if ( diff == 0 ) {
loc = -1;
}
break;
}
}
return loc;
} /* findInsertPoint */
static XP_Bool
addDictToState( const wchar_t* wPath, XP_U16 index, void* ctxt )
{
GameInfoState* giState = (GameInfoState*)ctxt;
/* Let's display only the short form, but save the whole path */
wchar_t* wstr;
XP_U16 len;
XP_S16 loc; /* < 0 means skip it */
loc = findInsertPoint( wPath, giState->menuDicts,
giState->nMenuDicts );
if ( loc >= 0 ) {
/* make a copy of the long name */
len = wcslen( wPath ) + 1;
wstr = (wchar_t*)XP_MALLOC( giState->globals->mpool,
len * sizeof(wstr[0]) );
XP_MEMCPY( wstr, wPath, len*sizeof(wstr[0]) );
if ( !giState->menuDicts ) {
XP_ASSERT( giState->nMenuDicts == 0 );
XP_ASSERT( giState->capMenuDicts == 0 );
giState->capMenuDicts = MENUDICTS_INCR;
giState->menuDicts
= (wchar_t**)XP_MALLOC( giState->globals->mpool,
giState->capMenuDicts
* sizeof(giState->menuDicts[0]) );
} else if ( giState->nMenuDicts == giState->capMenuDicts ) {
giState->capMenuDicts += MENUDICTS_INCR;
giState->menuDicts
= (wchar_t**)XP_REALLOC( giState->globals->mpool,
giState->menuDicts,
giState->capMenuDicts
* sizeof(giState->menuDicts[0]) );
}
if ( loc < giState->nMenuDicts ) {
XP_MEMMOVE( &giState->menuDicts[loc+1], &giState->menuDicts[loc],
(giState->nMenuDicts - loc)
* sizeof(giState->menuDicts[0]) );
}
giState->menuDicts[loc] = wstr;
++giState->nMenuDicts;
}
return XP_FALSE;
} /* addDictToState */
static void
addDictsToMenu( GameInfoState* giState )
{
wchar_t* shortname;
wchar_t shortPath[CE_MAX_PATH_LEN+1];
XP_U16 i, nMenuDicts = giState->nMenuDicts;
XP_S16 sel = 0;
/* insert the short names in the menu */
for ( i = 0; i < nMenuDicts; ++i ) {
wchar_t* wPath = giState->menuDicts[i];
shortname = wbname( shortPath, sizeof(shortPath), wPath );
SendDlgItemMessage( giState->hDlg, IDC_DICTCOMBO, CB_ADDSTRING, 0,
(long)shortname );
if ( giState->newDictName[0] != 0 && sel == 0 ) {
XP_UCHAR buf[CE_MAX_PATH_LEN+1];
WideCharToMultiByte( CP_ACP, 0, wPath, -1, buf, sizeof(buf),
NULL, NULL );
if ( 0 == XP_STRCMP( buf, giState->newDictName ) ) {
sel = i;
}
}
}
SendDlgItemMessage( giState->hDlg, IDC_DICTCOMBO, CB_SETCURSEL, sel, 0L );
} /* addDictsToMenu */
static void
cleanupGameInfoState( GameInfoState* giState )
{
if ( !!giState->menuDicts ) {
XP_U16 nMenuDicts = giState->nMenuDicts;
XP_U16 i;
for ( i = 0; i < nMenuDicts; ++i ) {
XP_FREE( giState->globals->mpool, giState->menuDicts[i] );
}
XP_FREE( giState->globals->mpool, giState->menuDicts );
giState->menuDicts = NULL;
}
} /* cleanupGameInfoState */
2003-11-20 17:26:35 +01:00
static void
loadFromGameInfo( HWND hDlg, CEAppGlobals* globals, GameInfoState* giState )
{
XP_U16 i;
CurGameInfo* gi = &globals->gameInfo;
2003-11-20 17:26:35 +01:00
#ifndef XWFEATURE_STANDALONE_ONLY
wchar_t* roles[] = { L"Standalone", L"Host", L"Guest" };
for ( i = 0; i < (sizeof(roles)/sizeof(roles[0])); ++i ) {
SendDlgItemMessage( hDlg, IDC_ROLECOMBO, CB_ADDSTRING, 0,
(long)roles[i] );
}
2003-11-20 17:26:35 +01:00
#endif
for ( i = 0; i < MAX_NUM_PLAYERS; ++i ) {
wchar_t widebuf[8];
2003-11-20 17:26:35 +01:00
/* put a string in the moronic combobox */
swprintf( widebuf, L"%d", i + 1 );
SendDlgItemMessage( hDlg, IDC_NPLAYERSCOMBO, CB_ADDSTRING, 0,
(long)widebuf );
}
newg_load( giState->newGameCtx, gi );
2003-11-20 17:26:35 +01:00
2005-11-27 21:13:42 +01:00
#ifndef STUBBED_DICT
if ( !!gi->dictName ) {
XP_LOGF( "%s: copying %s to giState->newDictName",
__FUNCTION__, gi->dictName );
XP_MEMCPY( giState->newDictName, gi->dictName,
(XP_U16)XP_STRLEN(gi->dictName)+1 );
2003-11-20 17:26:35 +01:00
}
if ( giState->isNewGame ) {
(void)ceLocateNDicts( MPPARM(globals->mpool) globals->hInst,
CE_MAXDICTS, addDictToState, giState );
} else {
wchar_t wPath[CE_MAX_PATH_LEN+1];
XP_ASSERT( gi->dictName[0] != '\0' );
MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, gi->dictName, -1,
wPath, sizeof(wPath)/sizeof(wPath[0]) );
(void)addDictToState( wPath, 0, giState );
}
addDictsToMenu( giState );
#endif
2003-11-20 17:26:35 +01:00
if ( !giState->isNewGame ) {
ceEnOrDisable( hDlg, IDC_DICTCOMBO, XP_FALSE );
ceEnOrDisable( hDlg, GIJUGGLE_BUTTON, XP_FALSE );
2003-11-20 17:26:35 +01:00
}
} /* loadFromGameInfo */
static void
stateToGameInfo( HWND hDlg, CEAppGlobals* globals, GameInfoState* giState )
{
CurGameInfo* gi = &globals->gameInfo;
XP_Bool timerOn;
newg_store( giState->newGameCtx, gi );
2003-11-20 17:26:35 +01:00
/* dictionary */ {
int sel;
sel = SendDlgItemMessage( hDlg, IDC_DICTCOMBO, CB_GETCURSEL, 0, 0L );
if ( sel >= 0 ) {
WideCharToMultiByte( CP_ACP, 0, giState->menuDicts[sel], -1,
giState->newDictName,
sizeof(giState->newDictName), NULL, NULL );
}
replaceStringIfDifferent( MPPARM(globals->mpool) &gi->dictName,
giState->newDictName );
}
2003-11-20 17:26:35 +01:00
/* timer */
timerOn = ceGetChecked( hDlg, TIMER_CHECK );
gi->timerEnabled = timerOn;
if ( timerOn ) {
XP_UCHAR numBuf[10];
XP_U16 len = sizeof(numBuf);
ceGetDlgItemText( hDlg, TIMER_EDIT, numBuf, &len );
if ( len > 0 ) {
XP_U16 num = atoi( numBuf );
gi->gameSeconds = num * 60;
}
}
/* preferences */
if ( giState->prefsChanged ) {
loadCurPrefsFromState( globals, &globals->appPrefs, gi,
&giState->prefsPrefs );
2003-11-20 17:26:35 +01:00
}
LOG_RETURN_VOID();
2003-11-20 17:26:35 +01:00
} /* stateToGameInfo */
static void
handlePrefsButton( HWND hDlg, CEAppGlobals* globals, GameInfoState* giState )
2003-11-20 17:26:35 +01:00
{
2004-04-14 05:57:59 +02:00
CePrefsDlgState state;
2003-11-20 17:26:35 +01:00
/* need to keep my stuff in a temporary place and to read back out of it
if launched a second time before the user's cancelled or not out of
the calling dlg.*/
if ( WrapPrefsDialog( hDlg, globals, &state, &giState->prefsPrefs,
giState->isNewGame ) ) {
giState->prefsChanged = XP_TRUE;
2004-05-26 06:39:29 +02:00
giState->colorsChanged = state.colorsChanged;
2003-11-20 17:26:35 +01:00
/* nothing to do until user finally does confirm the parent dialog */
}
} /* handlePrefsButton */
2003-11-20 17:26:35 +01:00
#ifndef XWFEATURE_STANDALONE_ONLY
static void
handleConnOptionsButton( HWND hDlg, CEAppGlobals* globals,
GameInfoState* giState )
{
CeConnDlgState state;
if ( WrapConnsDlg( hDlg, globals, &giState->prefsPrefs.addrRec,
&state ) ) {
XP_MEMCPY( &giState->prefsPrefs.addrRec, &state.addrRec,
sizeof(giState->prefsPrefs.addrRec) );
giState->addrChanged = XP_TRUE;
}
}
#endif
static XP_U16
resIDForCol( XP_U16 player, NewGameColumn col )
{
XP_U16 resID;
switch ( col ) {
case NG_COL_REMOTE:
resID = REMOTE_CHECK1;
break;
case NG_COL_ROBOT:
resID = ROBOT_CHECK1;
break;
case NG_COL_NAME:
resID = NAME_EDIT1;
break;
case NG_COL_PASSWD:
resID = PASS_EDIT1;
break;
default:
XP_ASSERT( 0 );
}
return resID + ( player * NUM_COLS );
} /* resIDForCol */
static XP_U16
resIDForAttr( NewGameAttr attr )
{
XP_U16 resID;
switch( attr ) {
case NG_ATTR_NPLAYERS:
resID = IDC_NPLAYERSCOMBO;
break;
case NG_ATTR_ROLE:
resID = IDC_ROLECOMBO;
break;
}
return resID;
} /* resIDForAttr */
2003-11-20 17:26:35 +01:00
static void
ceEnableColProc( void* closure, XP_U16 player, NewGameColumn col,
XP_Bool enable )
2003-11-20 17:26:35 +01:00
{
GameInfoState* giState = (GameInfoState*)closure;
ceShowOrHide( giState->hDlg, resIDForCol( player, col ), enable );
}
2003-11-20 17:26:35 +01:00
static void
ceEnableAttrProc( void* closure, NewGameAttr attr, XP_Bool enable )
{
GameInfoState* giState = (GameInfoState*)closure;
XP_U16 resID = resIDForAttr( attr );
ceEnOrDisable( giState->hDlg, resID, enable );
} /* ceEnableAttrProc */
static void
ceGetColProc( void* closure, XP_U16 player, NewGameColumn col,
NgCpCallbk cpcb, const void* cpClosure )
{
NGValue value;
GameInfoState* giState = (GameInfoState*)closure;
XP_U16 resID = resIDForCol( player, col );
XP_UCHAR txt[128];
XP_U16 len;
2003-11-20 17:26:35 +01:00
switch ( col ) {
case NG_COL_REMOTE:
case NG_COL_ROBOT:
value.ng_bool = ceGetChecked( giState->hDlg, resID );
break;
case NG_COL_NAME:
case NG_COL_PASSWD:
len = sizeof(txt);
ceGetDlgItemText( giState->hDlg, resID, txt, &len );
value.ng_cp = &txt[0];
break;
default:
XP_ASSERT(0);
2003-11-20 17:26:35 +01:00
}
(*cpcb)( value, cpClosure );
} /* ceGetColProc */
static void
ceSetColProc( void* closure, XP_U16 player, NewGameColumn col,
const NGValue value )
{
GameInfoState* giState = (GameInfoState*)closure;
XP_U16 resID = resIDForCol( player, col );
const XP_UCHAR* cp;
switch( col ) {
case NG_COL_PASSWD:
case NG_COL_NAME:
if ( NULL == value.ng_cp ) {
cp = "";
} else {
cp = value.ng_cp;
}
ceSetDlgItemText( giState->hDlg, resID, cp );
break;
case NG_COL_REMOTE:
case NG_COL_ROBOT:
ceSetChecked( giState->hDlg, resID, value.ng_bool );
break;
default:
XP_ASSERT(0);
}
}
static void
ceSetAttrProc(void* closure, NewGameAttr attr, const NGValue value )
{
GameInfoState* giState = (GameInfoState*)closure;
XP_U16 resID = resIDForAttr( attr );
XP_U16 val = value.ng_u16;
LOG_FUNC();
switch ( attr ) {
case NG_ATTR_NPLAYERS:
--val; /* adjust: it's 1-based */
case NG_ATTR_ROLE:
SendDlgItemMessage( giState->hDlg, resID, CB_SETCURSEL, val, 0L );
break;
}
} /* ceSetAttrProc */
static XP_U16
playerFromID( XP_U16 id, XP_U16 base )
{
XP_U16 player;
player = (id - base) / NUM_COLS;
/* XP_LOGF( "%s: looks like row %d", __FUNCTION__, player ); */
return player;
}
static void
handleColChecked( GameInfoState* giState, XP_U16 id, XP_U16 base,
NewGameColumn col )
{
NGValue value;
XP_U16 player = playerFromID( id, base );
value.ng_bool = ceGetChecked( giState->hDlg, id );
newg_colChanged( giState->newGameCtx, player, col, value );
}
2003-11-20 17:26:35 +01:00
LRESULT CALLBACK
GameInfo(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
CEAppGlobals* globals;
XP_U16 id;
GameInfoState* giState;
if ( message == WM_INITDIALOG ) {
SetWindowLong( hDlg, GWL_USERDATA, lParam );
giState = (GameInfoState*)lParam;
giState->hDlg = hDlg;
2003-11-20 17:26:35 +01:00
globals = giState->globals;
giState->newGameCtx = newg_make( MPPARM(globals->mpool)
giState->isNewGame,
ceEnableColProc,
ceEnableAttrProc,
ceGetColProc,
ceSetColProc,
ceSetAttrProc,
giState );
2003-11-20 17:26:35 +01:00
loadFromGameInfo( hDlg, globals, giState );
loadStateFromCurPrefs( globals, &globals->appPrefs, &globals->gameInfo,
2003-11-20 17:26:35 +01:00
&giState->prefsPrefs );
if ( giState->isNewGame ) {
(void)SetWindowText( hDlg, L"New game" );
}
ceStackButtonsRight( globals, hDlg );
2003-11-20 17:26:35 +01:00
return TRUE;
} else {
giState = (GameInfoState*)GetWindowLong( hDlg, GWL_USERDATA );
2004-05-26 06:39:29 +02:00
if ( !!giState ) {
globals = giState->globals;
2003-11-20 17:26:35 +01:00
2004-05-26 06:39:29 +02:00
switch (message) {
case WM_COMMAND:
id = LOWORD(wParam);
switch( id ) {
2003-11-20 17:26:35 +01:00
2004-05-26 06:39:29 +02:00
case ROBOT_CHECK1:
case ROBOT_CHECK2:
case ROBOT_CHECK3:
case ROBOT_CHECK4:
handleColChecked( giState, id, ROBOT_CHECK1,
NG_COL_ROBOT );
2004-05-26 06:39:29 +02:00
break;
2003-11-20 17:26:35 +01:00
#ifndef XWFEATURE_STANDALONE_ONLY
2004-05-26 06:39:29 +02:00
case REMOTE_CHECK1:
case REMOTE_CHECK2:
case REMOTE_CHECK3:
case REMOTE_CHECK4:
handleColChecked( giState, id, REMOTE_CHECK1,
NG_COL_REMOTE );
2004-05-26 06:39:29 +02:00
break;
2003-11-20 17:26:35 +01:00
#endif
2004-05-26 06:39:29 +02:00
case IDC_NPLAYERSCOMBO:
if ( HIWORD(wParam) == CBN_SELCHANGE ) {
if ( giState->isNewGame ) { /* ignore if in info
mode */
NGValue value;
value.ng_u16 = 1 + (XP_U16)
SendDlgItemMessage( hDlg,
IDC_NPLAYERSCOMBO,
CB_GETCURSEL, 0, 0L);
newg_attrChanged( giState->newGameCtx,
NG_ATTR_NPLAYERS, value );
2004-05-26 06:39:29 +02:00
}
2003-11-20 17:26:35 +01:00
}
2004-05-26 06:39:29 +02:00
break;
#ifndef XWFEATURE_STANDALONE_ONLY
2004-05-26 06:39:29 +02:00
case IDC_ROLECOMBO:
if ( HIWORD(wParam) == CBN_SELCHANGE ) {
if ( giState->isNewGame ) { /* ignore if in info
mode */
NGValue value;
value.ng_role =
(Connectedness)SendDlgItemMessage( hDlg,
IDC_ROLECOMBO,
CB_GETCURSEL, 0,
0L);
newg_attrChanged( giState->newGameCtx,
NG_ATTR_ROLE, value );
/* If we've switched to a state where we'll be
connecting */
if ( value.ng_role != SERVER_STANDALONE ) {
handleConnOptionsButton( hDlg, globals,
giState );
}
2004-05-26 06:39:29 +02:00
}
2003-11-20 17:26:35 +01:00
}
2004-05-26 06:39:29 +02:00
break;
#endif
case GIJUGGLE_BUTTON:
XP_ASSERT( giState->isNewGame );
newg_juggle( giState->newGameCtx );
break;
2004-05-26 06:39:29 +02:00
case OPTIONS_BUTTON:
handlePrefsButton( hDlg, globals, giState );
2004-05-26 06:39:29 +02:00
break;
2003-11-20 17:26:35 +01:00
2004-05-26 06:39:29 +02:00
case IDOK:
stateToGameInfo( hDlg, globals, giState );
case IDCANCEL:
EndDialog(hDlg, id);
giState->userCancelled = id == IDCANCEL;
cleanupGameInfoState( giState );
newg_destroy( giState->newGameCtx );
2004-05-26 06:39:29 +02:00
return TRUE;
}
break;
/* case WM_CLOSE: */
/* EndDialog(hDlg, id); */
/* return TRUE; */
/* default: */
/* return DefWindowProc(hDlg, message, wParam, lParam); */
2003-11-20 17:26:35 +01:00
}
}
}
return FALSE;
} /* GameInfo */