mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-11-18 10:08:29 +01:00
953 lines
29 KiB
C
953 lines
29 KiB
C
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
|
|
/*
|
|
* Copyright 1999 - 2001 by Eric House (fixin@peak.org). All rights reserved.
|
|
*
|
|
* 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 <PalmTypes.h>
|
|
#include <Form.h>
|
|
#include <List.h>
|
|
#include <Chars.h> /* for nextFieldChr */
|
|
#include <Graffiti.h> /* for GrfSetState */
|
|
#include <Event.h>
|
|
#ifdef HS_DUO_SUPPORT
|
|
# include <Hs.h>
|
|
#endif
|
|
|
|
#include "callback.h"
|
|
#include "comtypes.h"
|
|
#include "palmmain.h"
|
|
#include "comms.h"
|
|
#include "strutils.h"
|
|
#include "newgame.h"
|
|
#include "xwords4defines.h"
|
|
#include "dictui.h"
|
|
#include "palmdict.h"
|
|
#include "palmutil.h"
|
|
#include "palmir.h"
|
|
#include "prefsdlg.h"
|
|
#include "connsdlg.h"
|
|
|
|
static void handlePasswordTrigger( PalmAppGlobals* globals,
|
|
UInt16 controlID );
|
|
static void adjustVisibility( PalmAppGlobals* globals, XP_Bool canDraw );
|
|
static void setNPlayersAndAdjust( PalmAppGlobals* globals, Int16 chosen );
|
|
static void updatePlayerInfo( PalmAppGlobals* globals );
|
|
static XP_Bool tryFieldNavigationKey( XP_U16 key );
|
|
static void loadNewGameState( PalmAppGlobals* globals );
|
|
static void unloadNewGameState( PalmAppGlobals* globals );
|
|
static void setNameThatFits( PalmNewGameState* state );
|
|
#ifdef HS_DUO_SUPPORT
|
|
static XP_Bool tryDuoRockerKey( PalmAppGlobals* globals,XP_U16 key );
|
|
static XP_Bool considerGadgetFocus( PalmNewGameState* state, EventType* event );
|
|
#else
|
|
# define tryDuoRockerKey(g,key) XP_FALSE
|
|
#endif
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
static Boolean checkHiliteGadget(PalmAppGlobals* globals, EventType* event,
|
|
PalmNewGameState* state );
|
|
static void drawConnectGadgets( PalmAppGlobals* globals );
|
|
static void changeGadgetHilite( PalmAppGlobals* globals, UInt16 hiliteID );
|
|
|
|
#else
|
|
# define checkHiliteGadget(globals, event, state) XP_FALSE
|
|
# define drawConnectGadgets( globals )
|
|
#endif
|
|
|
|
#define IS_SERVER_GADGET(id) \
|
|
((id) >= XW_SOLO_GADGET_ID && (id) <= XW_CLIENT_GADGET_ID)
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
****************************************************************************/
|
|
Boolean
|
|
newGameHandleEvent( EventPtr event )
|
|
{
|
|
Boolean result = false;
|
|
EventType eventToPost; /* used only with OK button */
|
|
PalmAppGlobals* globals;
|
|
FormPtr form;
|
|
LocalPlayer* lp;
|
|
CurGameInfo* gi;
|
|
PalmNewGameState* state;
|
|
Int16 chosen;
|
|
XP_U16 i;
|
|
XP_U16 controlID;
|
|
XP_U16 index;
|
|
Boolean on;
|
|
Boolean canEdit;
|
|
|
|
CALLBACK_PROLOGUE();
|
|
|
|
globals = getFormRefcon();
|
|
gi = &globals->gameInfo;
|
|
state = &globals->newGameState;
|
|
|
|
switch ( event->eType ) {
|
|
|
|
case frmOpenEvent:
|
|
|
|
GlobalPrefsToLocal( globals );
|
|
|
|
loadNewGameState( globals );
|
|
|
|
form = FrmGetActiveForm();
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
sizeGadgetsForStrings( form,
|
|
getActiveObjectPtr( XW_SERVERTYPES_LIST_ID ),
|
|
XW_SOLO_GADGET_ID );
|
|
#endif
|
|
state->playerNumList =
|
|
getActiveObjectPtr( XW_NPLAYERS_LIST_ID );
|
|
XP_ASSERT( state->playerNumList != NULL );
|
|
|
|
setSelectorFromList( XW_NPLAYERS_SELECTOR_ID,
|
|
state->playerNumList,
|
|
gi->nPlayers - 1 );
|
|
|
|
XP_ASSERT( !!state->dictName );
|
|
setNameThatFits( state );
|
|
|
|
XP_ASSERT( !!globals->game.server );
|
|
|
|
canEdit = state->curServerHilite == SERVER_STANDALONE
|
|
|| globals->isNewGame;
|
|
|
|
/* load the fields from what we already have */
|
|
for ( lp = gi->players, i = 0; i < MAX_NUM_PLAYERS; ++lp, ++i ) {
|
|
XP_U16 offset = i * NUM_PLAYER_COLS;
|
|
ControlPtr check;
|
|
XP_UCHAR* name;
|
|
FieldPtr nameField;
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
Boolean isLocal = lp->isLocal;
|
|
check = getActiveObjectPtr(XW_REMOTE_1_CHECKBOX_ID + offset);
|
|
CtlSetValue( check, !isLocal );
|
|
#endif
|
|
check = getActiveObjectPtr(XW_ROBOT_1_CHECKBOX_ID+offset);
|
|
CtlSetValue( check, lp->isRobot );
|
|
|
|
nameField = getActiveObjectPtr(XW_PLAYERNAME_1_FIELD_ID+offset);
|
|
name = lp->name;
|
|
if ( !!name && !!*name ) {
|
|
FldInsert( nameField, (const char*)name,
|
|
XP_STRLEN((const char*)name) );
|
|
}
|
|
setFieldEditable( nameField, canEdit );
|
|
|
|
/* set up the password */
|
|
if ( !!lp->password ) {
|
|
CtlSetLabel( getActiveObjectPtr(
|
|
XW_PLAYERPASSWD_1_TRIGGER_ID+offset ),
|
|
"*" );
|
|
}
|
|
}
|
|
/* form = FrmGetActiveForm(); */
|
|
FrmSetFocus(form, FrmGetObjectIndex(form, XW_PLAYERNAME_1_FIELD_ID));
|
|
|
|
case frmUpdateEvent:
|
|
adjustVisibility( globals, XP_FALSE );
|
|
|
|
GrfSetState( false, false, false );
|
|
FrmDrawForm( FrmGetActiveForm() );
|
|
|
|
drawConnectGadgets( globals );
|
|
|
|
result = true;
|
|
break;
|
|
|
|
#ifdef BEYOND_IR
|
|
case connsSettingChgEvent:
|
|
XP_ASSERT( globals->isNewGame );
|
|
state->connsSettingChanged = XP_TRUE;
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HS_DUO_SUPPORT
|
|
case frmObjectFocusTakeEvent:
|
|
case frmObjectFocusLostEvent:
|
|
result = considerGadgetFocus( state, event );
|
|
break;
|
|
#endif
|
|
|
|
case penDownEvent:
|
|
result = checkHiliteGadget( globals, event, state );
|
|
break;
|
|
|
|
case keyDownEvent:
|
|
result = tryFieldNavigationKey( event->data.keyDown.chr )
|
|
|| tryDuoRockerKey( globals, event->data.keyDown.chr );
|
|
break;
|
|
|
|
case prefsChangedEvent:
|
|
state->forwardChange = true;
|
|
break;
|
|
|
|
case ctlEnterEvent:
|
|
switch ( event->data.ctlEnter.controlID ) {
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
case XW_REMOTE_1_CHECKBOX_ID:
|
|
case XW_REMOTE_2_CHECKBOX_ID:
|
|
case XW_REMOTE_3_CHECKBOX_ID:
|
|
case XW_REMOTE_4_CHECKBOX_ID:
|
|
#endif
|
|
case XW_DICT_SELECTOR_ID:
|
|
case XW_NPLAYERS_SELECTOR_ID:
|
|
if ( !globals->isNewGame ) {
|
|
result = true;
|
|
beep();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ctlSelectEvent:
|
|
result = true;
|
|
controlID = event->data.ctlSelect.controlID;
|
|
on = event->data.ctlSelect.on;
|
|
switch ( controlID ) {
|
|
|
|
case XW_ROBOT_1_CHECKBOX_ID:
|
|
case XW_ROBOT_2_CHECKBOX_ID:
|
|
case XW_ROBOT_3_CHECKBOX_ID:
|
|
case XW_ROBOT_4_CHECKBOX_ID:
|
|
index = (controlID - XW_ROBOT_1_CHECKBOX_ID) / NUM_PLAYER_COLS;
|
|
state->isRobot[index] = on;
|
|
adjustVisibility( globals, XP_TRUE );
|
|
break;
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
case XW_REMOTE_1_CHECKBOX_ID:
|
|
case XW_REMOTE_2_CHECKBOX_ID:
|
|
case XW_REMOTE_3_CHECKBOX_ID:
|
|
case XW_REMOTE_4_CHECKBOX_ID:
|
|
XP_ASSERT( state->curServerHilite == SERVER_ISSERVER );
|
|
index = (controlID - XW_REMOTE_1_CHECKBOX_ID) / NUM_PLAYER_COLS;
|
|
state->isLocal[index] = !on;
|
|
state->curNPlayersLocal += on? -1:1;
|
|
adjustVisibility( globals, XP_TRUE );
|
|
break;
|
|
#endif
|
|
|
|
case XW_NPLAYERS_SELECTOR_ID:
|
|
XP_ASSERT( globals->isNewGame );
|
|
chosen = LstPopupList( state->playerNumList );
|
|
if ( chosen >= 0 ) {
|
|
setSelectorFromList( XW_NPLAYERS_SELECTOR_ID,
|
|
state->playerNumList,
|
|
chosen );
|
|
++chosen; /* chosen is 0-based */
|
|
if (state->curServerHilite==SERVER_ISCLIENT) {
|
|
state->curNPlayersLocal = chosen;
|
|
XP_ASSERT( state->curNPlayersLocal <= MAX_NUM_PLAYERS );
|
|
} else {
|
|
state->curNPlayersTotal = chosen;
|
|
}
|
|
setNPlayersAndAdjust( globals, chosen );
|
|
}
|
|
break;
|
|
|
|
case XW_DICT_SELECTOR_ID:
|
|
XP_ASSERT( globals->isNewGame );
|
|
globals->dictuiForBeaming = false;
|
|
FrmPopupForm( XW_DICTINFO_FORM );
|
|
|
|
/* popup dict selection dialog -- or maybe just a list if there
|
|
are no preferences to set. The results should all be
|
|
cancellable, so don't delete the existing dictionary (if
|
|
any) until OK is chosen */
|
|
break;
|
|
|
|
case XW_OK_BUTTON_ID:
|
|
|
|
/* if we put up the prefs form from within this one and the user
|
|
clicked ok, we need to make sure the main form gets the
|
|
notification so it can make use of any changes. This event
|
|
needs to arrive before the newGame event so any changes will
|
|
be incorporated. */
|
|
if ( state->forwardChange ) {
|
|
eventToPost.eType = prefsChangedEvent;
|
|
EvtAddEventToQueue( &eventToPost );
|
|
state->forwardChange = false;
|
|
}
|
|
|
|
if ( globals->isNewGame ) {
|
|
updatePlayerInfo( globals );
|
|
|
|
eventToPost.eType = newGameOkEvent;
|
|
EvtAddEventToQueue( &eventToPost );
|
|
globals->postponeDraw = true;
|
|
|
|
} else if ( state->curServerHilite
|
|
== SERVER_STANDALONE ) {
|
|
updatePlayerInfo( globals );
|
|
}
|
|
|
|
unloadNewGameState( globals );
|
|
|
|
FrmReturnToForm( 0 );
|
|
break;
|
|
|
|
case XW_CANCEL_BUTTON_ID:
|
|
unloadNewGameState( globals );
|
|
eventToPost.eType = newGameCancelEvent;
|
|
EvtAddEventToQueue( &eventToPost );
|
|
FrmReturnToForm( 0 );
|
|
break;
|
|
|
|
case XW_PREFS_BUTTON_ID:
|
|
/* bring up with the this-game tab selected */
|
|
XP_ASSERT( !!globals->prefsDlgState );
|
|
globals->prefsDlgState->stateTypeIsGlobal = false;
|
|
FrmPopupForm( XW_PREFS_FORM );
|
|
break;
|
|
|
|
case XW_PLAYERPASSWD_1_TRIGGER_ID:
|
|
case XW_PLAYERPASSWD_2_TRIGGER_ID:
|
|
case XW_PLAYERPASSWD_3_TRIGGER_ID:
|
|
case XW_PLAYERPASSWD_4_TRIGGER_ID:
|
|
handlePasswordTrigger( globals, controlID );
|
|
break;
|
|
|
|
default: /* one of the password selectors? */
|
|
result = false;
|
|
}
|
|
break;
|
|
|
|
case dictSelectedEvent:
|
|
/* posted by the form we raise when user clicks Dictionary selector
|
|
above. */
|
|
if ( state->dictName != NULL ) {
|
|
XP_FREE( globals->mpool, state->dictName );
|
|
}
|
|
state->dictName =
|
|
((DictSelectedData*)&event->data.generic)->dictName;
|
|
setNameThatFits( state );
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CALLBACK_EPILOGUE();
|
|
return result;
|
|
} /* newGameHandleEvent */
|
|
|
|
static void
|
|
setNameThatFits( PalmNewGameState* state )
|
|
{
|
|
RectangleType rect;
|
|
XP_U16 width;
|
|
XP_U16 len = XP_STRLEN( (const char*)state->dictName );
|
|
|
|
XP_MEMCPY( state->shortDictName, state->dictName, len + 1 );
|
|
|
|
/* The width available is the cancel button's left minus ours */
|
|
getObjectBounds( XW_CANCEL_BUTTON_ID, &rect );
|
|
width = rect.topLeft.x;
|
|
getObjectBounds( XW_DICT_SELECTOR_ID, &rect );
|
|
width -= (rect.topLeft.x + 6);
|
|
|
|
for ( ; FntCharsWidth( (const char*)state->dictName, len ) > width; --len ) {
|
|
/* do nothing */
|
|
}
|
|
|
|
state->shortDictName[len] = '\0';
|
|
CtlSetLabel( getActiveObjectPtr( XW_DICT_SELECTOR_ID ),
|
|
(const char*)state->shortDictName );
|
|
} /* setNameThatFits */
|
|
|
|
static XP_U16
|
|
countLocalIn( PalmNewGameState* state, XP_U16 nPlayers )
|
|
{
|
|
XP_U16 nLocal = 0;
|
|
XP_U16 i;
|
|
|
|
for ( i = 0; i < nPlayers; ++i ) {
|
|
if ( state->isLocal[i] ) {
|
|
++nLocal;
|
|
}
|
|
}
|
|
|
|
return nLocal;
|
|
} /* countLocalIn */
|
|
|
|
/* If we're in GUEST mode, only local players are visible, and so this means
|
|
* an increase in the number of local players. If we're in a different mode
|
|
* then it means a simple increase in all players. Only the first case is
|
|
* difficult, because if the number's getting larger we need to confirm that
|
|
* there's another local player to show, and if there's not we need to
|
|
* convert the first non-local player.
|
|
*/
|
|
static void
|
|
setNPlayersAndAdjust( PalmAppGlobals* globals, Int16 chosen )
|
|
{
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
|
|
if ( state->curServerHilite == SERVER_ISCLIENT ) {
|
|
XP_U16 i;
|
|
XP_S16 nRemote = 0;
|
|
XP_S16 nLocal = 0;
|
|
|
|
/* find the first non-local player */
|
|
for ( i = 0; i < MAX_NUM_PLAYERS; ++i ) {
|
|
if ( state->isLocal[i] ) {
|
|
++nLocal;
|
|
} else {
|
|
++nRemote;
|
|
}
|
|
}
|
|
|
|
/* Make as many local as necessary */
|
|
for ( i = 0; nLocal < chosen && i < MAX_NUM_PLAYERS; ++i ) {
|
|
if ( !state->isLocal[i] ) {
|
|
state->isLocal[i] = true;
|
|
setBooleanCtrl( XW_REMOTE_1_CHECKBOX_ID +
|
|
(i * NUM_PLAYER_COLS), false );
|
|
++nLocal;
|
|
--nRemote;
|
|
}
|
|
}
|
|
|
|
state->curNPlayersLocal = chosen;
|
|
XP_ASSERT( state->curNPlayersLocal <= MAX_NUM_PLAYERS );
|
|
state->curNPlayersTotal = chosen + nRemote;
|
|
XP_ASSERT( state->curNPlayersTotal <= MAX_NUM_PLAYERS );
|
|
} else {
|
|
state->curNPlayersTotal = chosen;
|
|
state->curNPlayersLocal = countLocalIn( state, chosen );
|
|
XP_ASSERT( state->curNPlayersLocal <= MAX_NUM_PLAYERS );
|
|
}
|
|
#endif
|
|
|
|
adjustVisibility( globals, XP_TRUE );
|
|
} /* setNPlayersAndAdjust */
|
|
|
|
static Boolean
|
|
tryFieldNavigationKey( XP_U16 key )
|
|
{
|
|
FormPtr form;
|
|
Int16 curFocus, nextFocus, change;
|
|
UInt16 nObjects;
|
|
|
|
if ( key == prevFieldChr ) {
|
|
change = -1;
|
|
} else if ( key == nextFieldChr ) {
|
|
change = 1;
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
form = FrmGetActiveForm();
|
|
curFocus = nextFocus = FrmGetFocus( form );
|
|
nObjects = FrmGetNumberOfObjects(form);
|
|
|
|
/* find the next (in either direction) usable field */
|
|
for ( ; ; ) {
|
|
nextFocus += change;
|
|
|
|
if ( nextFocus == nObjects ) {
|
|
nextFocus = 0;
|
|
} else if ( nextFocus < 0 ) {
|
|
nextFocus = nObjects-1;
|
|
}
|
|
|
|
if ( nextFocus == curFocus ) {
|
|
break;
|
|
} else if ( FrmGetObjectType(form, nextFocus) != frmFieldObj ) {
|
|
continue;
|
|
} else {
|
|
FieldPtr field = FrmGetObjectPtr( form, nextFocus );
|
|
FieldAttrType attrs;
|
|
FldGetAttributes( field, &attrs );
|
|
if ( attrs.usable ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FrmSetFocus( form, nextFocus );
|
|
return true;
|
|
} /* tryFieldNavigationKey */
|
|
|
|
#ifdef HS_DUO_SUPPORT
|
|
#ifdef DEBUG
|
|
static XP_UCHAR*
|
|
keyToStr( XP_U16 key )
|
|
{
|
|
#define keyCase(k) case (k): return #k
|
|
switch( key ) {
|
|
keyCase(vchrRockerUp);
|
|
keyCase(vchrRockerDown);
|
|
keyCase(vchrRockerLeft);
|
|
keyCase(vchrRockerRight);
|
|
keyCase(vchrRockerCenter);
|
|
default:
|
|
return "huh?";
|
|
}
|
|
#undef keyCase
|
|
}
|
|
#endif
|
|
|
|
static XP_Bool
|
|
tryDuoRockerKey( PalmAppGlobals* globals, XP_U16 key )
|
|
{
|
|
XP_Bool result = XP_FALSE;
|
|
XP_U16 focusID;
|
|
FormPtr form;
|
|
|
|
switch( key ) {
|
|
case vchrRockerUp:
|
|
case vchrRockerDown:
|
|
case vchrRockerLeft:
|
|
case vchrRockerRight:
|
|
XP_LOGF( "got rocker key: %s", keyToStr(key) );
|
|
result = XP_FALSE;
|
|
break;
|
|
case vchrRockerCenter:
|
|
/* if one of the gadgets is focussed, "tap" it. */
|
|
XP_LOGF( "got rocker key: %s", keyToStr(key) );
|
|
form = FrmGetActiveForm();
|
|
focusID = FrmGetObjectId( form, FrmGetFocus( form ) );
|
|
if ( IS_SERVER_GADGET( focusID ) ) {
|
|
changeGadgetHilite( globals, focusID );
|
|
result = XP_TRUE;
|
|
} else {
|
|
XP_LOGF( "%d not server gadget", focusID );
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return result;
|
|
} /* tryDuoRockerKey */
|
|
#endif
|
|
|
|
static void
|
|
adjustVisibility( PalmAppGlobals* globals, XP_Bool canDraw )
|
|
{
|
|
FormPtr form = FrmGetActiveForm();
|
|
short i;
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
XP_Bool isNewGame = globals->isNewGame;
|
|
|
|
Connectedness curServerHilite = state->curServerHilite;
|
|
Boolean canShowRemote = curServerHilite != SERVER_STANDALONE;
|
|
Boolean isClient = curServerHilite == SERVER_ISCLIENT;
|
|
XP_U16 nShown = 0;
|
|
Boolean canEdit = (curServerHilite == SERVER_STANDALONE) || isNewGame;
|
|
XP_U16 nToShow = (isClient && isNewGame)?
|
|
state->curNPlayersLocal:state->curNPlayersTotal;
|
|
|
|
/* It's illegal for there to be 0 players selected. So if that ever
|
|
happens, make the first player local. And beep? */
|
|
if ( nToShow == 0 ) {
|
|
XP_ASSERT( isClient ); /* the only way this can happen is if someone
|
|
sets type to SERVER_ISCLIENT when there
|
|
are no local players. */
|
|
state->isLocal[0] = true;
|
|
nToShow = state->curNPlayersLocal = 1;
|
|
setBooleanCtrl( XW_REMOTE_1_CHECKBOX_ID, false );
|
|
}
|
|
|
|
if ( canShowRemote && isClient ) {
|
|
canShowRemote = !isNewGame;
|
|
}
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
disOrEnable( form, XW_LOCAL_LABEL_ID, canShowRemote );
|
|
if ( canShowRemote ) {
|
|
disOrEnable( form, XW_TOTALP_LABEL_ID, XP_TRUE );
|
|
} else {
|
|
disOrEnable( form, XW_LOCALP_LABEL_ID, XP_TRUE );
|
|
}
|
|
#endif
|
|
|
|
for ( i = 0; i < MAX_NUM_PLAYERS; ++i ) {
|
|
short offset = NUM_PLAYER_COLS * i;
|
|
Boolean lineVisible = nShown < nToShow;
|
|
Boolean isLocal;
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
Boolean showRemote;
|
|
Boolean remoteChecked = !state->isLocal[i];
|
|
|
|
if ( isClient && lineVisible && remoteChecked && isNewGame ) {
|
|
lineVisible = false;
|
|
}
|
|
#endif
|
|
/* Since the user of a device can change at will whether a local
|
|
player is a robot, we don't show that attribute except when it's
|
|
for a local player; don't keep track of what's going on on the
|
|
other device. */
|
|
isLocal = lineVisible;
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
showRemote = lineVisible && canShowRemote;
|
|
isLocal = isLocal &&
|
|
(curServerHilite == SERVER_STANDALONE
|
|
|| (showRemote && !remoteChecked)
|
|
|| (isClient && isNewGame) );
|
|
|
|
/* show local/remote checkbox if not standalone */
|
|
disOrEnable( form, XW_REMOTE_1_CHECKBOX_ID + offset,
|
|
lineVisible && showRemote );
|
|
#endif
|
|
/* show name no matter what (if line's showing) */
|
|
disOrEnable( form, XW_PLAYERNAME_1_FIELD_ID + offset,
|
|
lineVisible && (isLocal || !isNewGame) );
|
|
|
|
if ( lineVisible ) {
|
|
FieldPtr nameField =
|
|
getActiveObjectPtr(XW_PLAYERNAME_1_FIELD_ID + offset);
|
|
setFieldEditable( nameField, canEdit );
|
|
if ( canDraw ) {
|
|
FldDrawField( nameField );
|
|
}
|
|
}
|
|
|
|
/* show robot checkbox if player is local */
|
|
disOrEnable( form, XW_ROBOT_1_CHECKBOX_ID + offset, isLocal );
|
|
|
|
/* and show password if not a robot (and if local) */
|
|
disOrEnable( form, XW_PLAYERPASSWD_1_TRIGGER_ID + offset,
|
|
isLocal && !state->isRobot[i] );
|
|
|
|
if ( lineVisible ) {
|
|
++nShown;
|
|
}
|
|
XP_ASSERT( nShown <= MAX_NUM_PLAYERS );
|
|
}
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
XP_ASSERT( nShown > 0 );
|
|
setSelectorFromList( XW_NPLAYERS_SELECTOR_ID,
|
|
state->playerNumList, nShown - 1 );
|
|
#endif
|
|
} /* adjustVisibility */
|
|
|
|
/*
|
|
* Copy the local state into global state.
|
|
*/
|
|
static void
|
|
updatePlayerInfo( PalmAppGlobals* globals )
|
|
{
|
|
UInt16 i;
|
|
CurGameInfo* gi;
|
|
LocalPlayer* lp;
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
Connectedness curServerHilite = globals->newGameState.curServerHilite;
|
|
|
|
gi = &globals->gameInfo;
|
|
|
|
gi->nPlayers = curServerHilite == SERVER_ISCLIENT?
|
|
state->curNPlayersLocal: state->curNPlayersTotal;
|
|
XP_ASSERT( gi->nPlayers <= MAX_NUM_PLAYERS );
|
|
|
|
gi->boardSize = globals->prefsDlgState->curBdSize;
|
|
gi->serverRole = curServerHilite;
|
|
|
|
replaceStringIfDifferent( MPPARM(globals->mpool) &gi->dictName,
|
|
globals->newGameState.dictName );
|
|
|
|
for ( i = 0, lp = gi->players; i < MAX_NUM_PLAYERS; ++i, ++lp ) {
|
|
XP_UCHAR* name = NULL;
|
|
XP_UCHAR* passwd = NULL;
|
|
short offset = NUM_PLAYER_COLS * i;
|
|
XP_Bool isLocal = state->isLocal[i];
|
|
|
|
if ( isLocal ) {
|
|
MemPtr p = getActiveObjectPtr( offset +
|
|
XW_PLAYERNAME_1_FIELD_ID );
|
|
name = (XP_UCHAR*)FldGetTextPtr( p );
|
|
|
|
if ( name == NULL ) {
|
|
name = (XP_UCHAR*)"";
|
|
}
|
|
passwd = globals->newGameState.passwds[i];
|
|
}
|
|
|
|
lp->isRobot = state->isRobot[i];
|
|
lp->isLocal = isLocal;
|
|
|
|
replaceStringIfDifferent(MPPARM(globals->mpool) &lp->name, name);
|
|
replaceStringIfDifferent(MPPARM(globals->mpool) &lp->password, passwd);
|
|
}
|
|
|
|
#ifdef BEYOND_IR
|
|
if ( state->connsSettingChanged ) {
|
|
CommsAddrRec addr;
|
|
XP_U16 localPort;
|
|
|
|
comms_getAddr( globals->game.comms, &addr, &localPort );
|
|
|
|
addr.conType = state->connAddrs.conType;
|
|
if ( addr.conType == COMMS_CONN_IP ) {
|
|
addr.u.ip.port = state->connAddrs.remotePort;
|
|
addr.u.ip.ipAddr = state->connAddrs.remoteIP;
|
|
localPort = state->connAddrs.localPort;
|
|
}
|
|
comms_setAddr( globals->game.comms, &addr, localPort );
|
|
}
|
|
#endif
|
|
|
|
} /* updatePlayerInfo */
|
|
|
|
void
|
|
drawOneGadget( UInt16 id, char* text, Boolean hilite )
|
|
{
|
|
RectangleType divRect;
|
|
XP_U16 len = XP_STRLEN(text);
|
|
XP_U16 width = FntCharsWidth( text, len );
|
|
XP_U16 left;
|
|
|
|
getObjectBounds( id, &divRect );
|
|
WinDrawRectangleFrame( rectangleFrame, &divRect );
|
|
WinEraseRectangle( &divRect, 0 );
|
|
left = divRect.topLeft.x;
|
|
left += (divRect.extent.x - width) / 2;
|
|
WinDrawChars( text, len, left, divRect.topLeft.y );
|
|
if ( hilite ) {
|
|
WinInvertRectangle( &divRect, 0 );
|
|
}
|
|
} /* drawOneGadget */
|
|
|
|
/* Frame 'em, draw their text, and highlight the one that's selected
|
|
*/
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
|
|
#ifdef HS_DUO_SUPPORT
|
|
static void
|
|
drawFocusRingOnGadget()
|
|
{
|
|
FormPtr form = FrmGetActiveForm();
|
|
XP_U16 focusID = FrmGetObjectId( form, FrmGetFocus(form) );
|
|
if ( IS_SERVER_GADGET(focusID) ) {
|
|
Err err;
|
|
RectangleType rect;
|
|
|
|
getObjectBounds( focusID, &rect );
|
|
|
|
err = HsNavDrawFocusRing( form, focusID, 0, &rect,
|
|
hsNavFocusRingStyleObjectTypeDefault,
|
|
false );
|
|
XP_ASSERT( err == errNone );
|
|
}
|
|
} /* drawFocusRingOnGadget */
|
|
#endif
|
|
|
|
static void
|
|
drawConnectGadgets( PalmAppGlobals* globals )
|
|
{
|
|
UInt16 i;
|
|
ListPtr list = getActiveObjectPtr( XW_SERVERTYPES_LIST_ID );
|
|
XP_ASSERT( !!list );
|
|
|
|
for ( i = 0; i < 3; ++i ) {
|
|
char* text = LstGetSelectionText( list, i );
|
|
Boolean hilite = i == globals->newGameState.curServerHilite;
|
|
drawOneGadget( i + XW_SOLO_GADGET_ID, text, hilite );
|
|
}
|
|
|
|
#ifdef HS_DUO_SUPPORT
|
|
drawFocusRingOnGadget();
|
|
#endif
|
|
|
|
} /* drawConnectGadgets */
|
|
|
|
#ifdef HS_DUO_SUPPORT
|
|
static XP_Bool
|
|
considerGadgetFocus( PalmNewGameState* state, EventType* event )
|
|
{
|
|
XP_Bool result = XP_FALSE;
|
|
XP_Bool isTake;
|
|
XP_U16 eType = event->eType;
|
|
FormPtr form = FrmGetActiveForm();
|
|
XP_U16 objectID;
|
|
|
|
XP_ASSERT( eType == frmObjectFocusTakeEvent
|
|
|| eType == frmObjectFocusLostEvent );
|
|
XP_ASSERT( event->data.frmObjectFocusTake.formID == FrmGetActiveFormID() );
|
|
|
|
|
|
isTake = eType == frmObjectFocusTakeEvent;
|
|
if ( isTake ) {
|
|
objectID = event->data.frmObjectFocusTake.objectID;
|
|
} else {
|
|
objectID = event->data.frmObjectFocusLost.objectID;
|
|
}
|
|
|
|
/* docs say to return HANDLED for both take and lost */
|
|
result = IS_SERVER_GADGET( objectID );
|
|
|
|
if ( result ) {
|
|
Err err;
|
|
if ( isTake ) {
|
|
|
|
FrmSetFocus(form, FrmGetObjectIndex(form, objectID));
|
|
drawFocusRingOnGadget();
|
|
result = XP_TRUE;
|
|
/* } else { */
|
|
/* err = HsNavRemoveFocusRing( form ); */
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} /* considerGadgetFocus */
|
|
#endif
|
|
|
|
static void
|
|
changeGadgetHilite( PalmAppGlobals* globals, UInt16 hiliteID )
|
|
{
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
XP_Bool isNewGame = globals->isNewGame;
|
|
|
|
hiliteID -= XW_SOLO_GADGET_ID;
|
|
|
|
if ( hiliteID != state->curServerHilite ) {
|
|
/* if it's not a new game, don't recognize the change */
|
|
if ( isNewGame ) {
|
|
state->curServerHilite = hiliteID;
|
|
drawConnectGadgets( globals );
|
|
adjustVisibility( globals, XP_TRUE );
|
|
} else {
|
|
beep();
|
|
}
|
|
}
|
|
|
|
#ifdef BEYOND_IR
|
|
/* Even if it didn't change, pop the connections form */
|
|
if ( hiliteID != SERVER_STANDALONE ) {
|
|
if ( isNewGame || hiliteID==globals->newGameState.curServerHilite ) {
|
|
PopupConnsForm( globals, hiliteID, &state->connAddrs );
|
|
}
|
|
}
|
|
#endif
|
|
} /* changeGadgetHilite */
|
|
|
|
static Boolean
|
|
checkHiliteGadget( PalmAppGlobals* globals, EventType* event,
|
|
PalmNewGameState* state )
|
|
{
|
|
Boolean result = false;
|
|
UInt16 selGadget;
|
|
|
|
XP_ASSERT( &globals->newGameState == state );
|
|
|
|
result = penInGadget( event, &selGadget );
|
|
if ( result ) {
|
|
changeGadgetHilite( globals, selGadget );
|
|
}
|
|
|
|
return result;
|
|
} /* checkHiliteGadget */
|
|
#endif
|
|
|
|
/* If there's currently no password set, just let 'em set one. If there is
|
|
* one set, they need to know the old before setting the new.
|
|
*/
|
|
static void
|
|
handlePasswordTrigger( PalmAppGlobals* globals, UInt16 controlID )
|
|
{
|
|
UInt16 playerNum;
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
XP_UCHAR** password;
|
|
XP_UCHAR* name;
|
|
FieldPtr nameField;
|
|
XP_U16 len;
|
|
XP_UCHAR buf[32];
|
|
char* label;
|
|
|
|
playerNum = (controlID - XW_PLAYERPASSWD_1_TRIGGER_ID) / NUM_PLAYER_COLS;
|
|
XP_ASSERT( playerNum < MAX_NUM_PLAYERS );
|
|
|
|
password = &state->passwds[playerNum];
|
|
nameField = getActiveObjectPtr( XW_PLAYERNAME_1_FIELD_ID +
|
|
(NUM_PLAYER_COLS * playerNum) );
|
|
name = (XP_UCHAR*)FldGetTextPtr( nameField );
|
|
|
|
len = sizeof(buf);
|
|
if ( askPassword( globals, name, true, buf, &len ) ) {
|
|
|
|
if ( len == 0 ) {
|
|
buf[0] = '\0';
|
|
label = " ";
|
|
} else {
|
|
label = "*";
|
|
}
|
|
replaceStringIfDifferent(MPPARM(globals->mpool) password,
|
|
(unsigned char*)buf);
|
|
|
|
/* control owns the string passed in */
|
|
CtlSetLabel( getActiveObjectPtr( controlID ), label );
|
|
}
|
|
} /* handlePasswordTrigger */
|
|
|
|
static void
|
|
unloadNewGameState( PalmAppGlobals* globals )
|
|
{
|
|
XP_U16 i;
|
|
XP_UCHAR** passwd;
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
|
|
for ( passwd = state->passwds, i = 0;
|
|
i < MAX_NUM_PLAYERS; ++i, ++passwd ) {
|
|
if ( !!*passwd ) {
|
|
XP_FREE( globals->mpool, *passwd );
|
|
*passwd = NULL;
|
|
}
|
|
}
|
|
/* XP_WARNF( "freeing string 0x%lx", state->dictName ); */
|
|
XP_FREE( globals->mpool, state->dictName );
|
|
state->dictName = NULL;
|
|
} /* unloadNewGameState */
|
|
|
|
static void
|
|
loadNewGameState( PalmAppGlobals* globals )
|
|
{
|
|
CurGameInfo* gi = &globals->gameInfo;
|
|
PalmNewGameState* state = &globals->newGameState;
|
|
XP_U16 i;
|
|
LocalPlayer* lp;
|
|
|
|
XP_MEMSET( state, 0, sizeof(*state) );
|
|
|
|
state->dictName = copyString( MPPARM(globals->mpool) gi->dictName );
|
|
state->curServerHilite = gi->serverRole;
|
|
|
|
for ( i = 0, lp=gi->players; i < MAX_NUM_PLAYERS; ++i, ++lp ) {
|
|
state->isLocal[i] = lp->isLocal;
|
|
state->isRobot[i] = lp->isRobot;
|
|
state->passwds[i] = copyString( MPPARM(globals->mpool)
|
|
lp->password );
|
|
}
|
|
|
|
state->curNPlayersTotal = gi->nPlayers;
|
|
state->curNPlayersLocal = countLocalIn( state, gi->nPlayers );
|
|
XP_ASSERT( state->curNPlayersLocal <= MAX_NUM_PLAYERS );
|
|
|
|
#ifdef BEYOND_IR
|
|
{
|
|
CommsAddrRec addr;
|
|
comms_getAddr( globals->game.comms, &addr,
|
|
&state->connAddrs.localPort );
|
|
state->connAddrs.remotePort = addr.u.ip.port;
|
|
state->connAddrs.remoteIP = addr.u.ip.ipAddr;
|
|
state->connAddrs.conType = addr.conType;
|
|
}
|
|
#endif
|
|
|
|
} /* loadNewGameState */
|