Merge branch 'android_branch' into send_in_background

This commit is contained in:
eehouse@eehouse.org 2011-10-14 22:34:29 -07:00 committed by Andy2
commit 5afb0ae145
25 changed files with 307 additions and 230 deletions

View file

@ -83,11 +83,6 @@
>
</activity>
<activity android:name="LookupActivity"
android:configChanges="keyboardHidden|orientation"
android:theme="@android:style/Theme.Dialog"
/>
<receiver android:name="RelayReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>

View file

@ -24,6 +24,7 @@ local_DEFINES += \
-DDROP_BITMAPS \
-DDISABLE_EMPTYTRAY_UNDO \
-DDISABLE_TILE_SEL \
-DXWFEATURE_BOARDWORDS \
-DNODE_CAN_4 \
-DRELAY_ROOM_DEFAULT=\"\"\
-D__LITTLE_ENDIAN \

View file

@ -422,6 +422,21 @@ and_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
}
#endif
#ifdef XWFEATURE_BOARDWORDS
static void
and_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
{
if ( NULL != words ) {
UTIL_CBK_HEADER( "cellSquareHeld", "(Ljava/lang/String;)V" );
jstring jwords =
streamToJString( MPPARM(util->util.mpool) env, words );
(*env)->CallVoidMethod( env, util->jutil, mid, jwords );
(*env)->DeleteLocalRef( env, jwords );
UTIL_CBK_TAIL();
}
}
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
static void
and_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
@ -512,6 +527,10 @@ makeUtil( MPFORMAL JNIEnv** envp, jobject jutil, CurGameInfo* gi,
SET_PROC(playerScoreHeld);
#endif
#ifdef XWFEATURE_BOARDWORDS
SET_PROC(cellSquareHeld);
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
SET_PROC(addrChange);
#endif

View file

@ -1256,21 +1256,6 @@ Java_org_eehouse_android_xw4_jni_XwJNI_server_1endGame
XWJNI_END();
}
JNIEXPORT jstring JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_model_1getWordsPlayed
( JNIEnv* env, jclass C, jint gamePtr, jint nMoves )
{
jstring result;
XWJNI_START_GLOBALS();
XWStreamCtxt* stream = and_empty_stream( MPPARM(mpool) globals );
model_getWordsPlayed( state->game.model, nMoves, stream );
result = streamToJString( MPPARM(mpool) env, stream );
(*env)->DeleteLocalRef( env, result );
stream_destroy( stream );
XWJNI_END();
return result;
}
JNIEXPORT void JNICALL
Java_org_eehouse_android_xw4_jni_XwJNI_server_1sendChat
( JNIEnv* env, jclass C, jint gamePtr, jstring jmsg )

View file

@ -47,6 +47,18 @@
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView style="@style/config_separator"
android:text="@string/lang_label"
/>
<Spinner android:id="@+id/lang_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:prompt="@string/title_langs_list"
/>
<!-- players -->
<TextView style="@style/config_separator"
android:id="@+id/players_label"
@ -77,17 +89,6 @@
/>
</LinearLayout>
<TextView style="@style/config_separator"
android:text="@string/lang_label"
/>
<Spinner android:id="@+id/lang_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:drawSelectorOnTop="true"
android:prompt="@string/title_langs_list"
/>
<LinearLayout android:id="@+id/connect_set"
android:layout_width="fill_parent"
android:layout_height="wrap_content"

View file

@ -6,11 +6,12 @@
<!-- android:orientation="vertical" -->
<!-- > -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<org.eehouse.android.xw4.LookupView
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView android:id="@+id/summary"
android:layout_height="wrap_content"
@ -19,7 +20,7 @@
android:gravity="center"
/>
<ListView android:id="@+id/android:list"
<ListView android:id="@+id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:drawSelectorOnTop="false"
@ -32,5 +33,5 @@
/>
<!-- android:text="@string/button_done" -->
</LinearLayout>
</org.eehouse.android.xw4.LookupView>
<!-- </ScrollView> -->

View file

@ -30,8 +30,6 @@
<item android:title="@string/board_submenu_game">
<menu>
<item android:id="@+id/board_menu_lookup"
android:title="@string/button_lookup" />
<item android:id="@+id/board_menu_game_counts"
android:title="@string/board_menu_game_counts" />
<item android:id="@+id/board_menu_game_left"

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "cd ../../../../../; ant install"; -*- */
/*
* Copyright 2009-2010 by Eric House (xwords@eehouse.org). All
* Copyright 2009-2011 by Eric House (xwords@eehouse.org). All
* rights reserved.
*
* This program is free software; you can redistribute it and/or
@ -72,6 +72,7 @@ public class BoardActivity extends XWActivity
private static final int DLG_DELETED = DLG_OKONLY + 8;
private static final int DLG_INVITE = DLG_OKONLY + 9;
private static final int DLG_SCORES_BLK = DLG_OKONLY + 10;
private static final int DLG_LOOKUP = DLG_OKONLY + 11;
private static final int CHAT_REQUEST = 1;
private static final int SCREEN_ON_TIME = 10 * 60 * 1000; // 10 mins
@ -95,6 +96,7 @@ public class BoardActivity extends XWActivity
private static final String DLG_TITLESTR = "DLG_TITLESTR";
private static final String DLG_BYTES = "DLG_BYTES";
private static final String ROOM = "ROOM";
private static final String PWDNAME = "PWDNAME";
private static final String TOASTSTR = "TOASTSTR";
private static final String WORDS = "WORDS";
@ -138,6 +140,7 @@ public class BoardActivity extends XWActivity
private String m_room;
private String m_toastStr;
private String[] m_words;
private String m_pwdName;
private int m_missing;
private boolean m_haveInvited = false;
@ -277,6 +280,9 @@ public class BoardActivity extends XWActivity
break;
case ASK_PASSWORD_BLK:
if ( null == m_passwdLyt ) {
setupPasswdVars();
}
m_passwdEdit.setText( "", TextView.BufferType.EDITABLE );
ab = new AlertDialog.Builder( this )
.setTitle( m_dlgTitleStr )
@ -326,6 +332,15 @@ public class BoardActivity extends XWActivity
}
break;
case DLG_LOOKUP:
LookupView view = (LookupView)Utils.inflate( this, R.layout.lookup );
dialog = new AlertDialog.Builder( this )
.setView( view )
.create();
view.setDialog( dialog, DLG_LOOKUP );
view.setWords( m_words, m_gi.dictLang );
break;
default:
// just drop it; super.onCreateDialog likely failed
break;
@ -414,6 +429,7 @@ public class BoardActivity extends XWActivity
outState.putString( ROOM, m_room );
outState.putString( TOASTSTR, m_toastStr );
outState.putStringArray( WORDS, m_words );
outState.putString( PWDNAME, m_pwdName );
}
private void getBundledData( Bundle bundle )
@ -425,6 +441,7 @@ public class BoardActivity extends XWActivity
m_room = bundle.getString( ROOM );
m_toastStr = bundle.getString( TOASTSTR );
m_words = bundle.getStringArray( WORDS );
m_pwdName = bundle.getString( PWDNAME );
}
}
@ -573,10 +590,6 @@ public class BoardActivity extends XWActivity
case R.id.board_menu_values:
cmd = JNIThread.JNICmd.CMD_VALUES;
break;
case R.id.board_menu_lookup:
m_jniThread.handle( JNICmd.CMD_WORDS, 10000 );
break;
case R.id.board_menu_game_counts:
m_jniThread.handle( JNIThread.JNICmd.CMD_COUNTS_VALUES,
R.string.counts_values_title );
@ -993,6 +1006,16 @@ public class BoardActivity extends XWActivity
} );
}
@Override
public void cellSquareHeld( final String words )
{
post( new Runnable() {
public void run() {
launchLookup( wordsToArray( words ) );
}
} );
}
public void setTimer( int why, int when, int handle )
{
if ( null != m_timers[why] ) {
@ -1033,15 +1056,11 @@ public class BoardActivity extends XWActivity
public String askPassword( String name )
{
String fmt = getString( R.string.msg_ask_password );
m_dlgTitleStr = String.format( fmt, name );
// call this each time dlg created or will get exception
// for reusing m_passwdLyt
m_pwdName = name;
setupPasswdVars();
if ( null == m_passwdEdit ) {
m_passwdLyt =
(LinearLayout)Utils.inflate( BoardActivity.this,
R.layout.passwd_view );
m_passwdEdit = (EditText)m_passwdLyt.findViewById( R.id.edit );
}
waitBlockingDialog( ASK_PASSWORD_BLK, 0 );
String result = null; // means cancelled
@ -1572,11 +1591,17 @@ public class BoardActivity extends XWActivity
private void launchLookup( String[] words )
{
Intent intent = new Intent( this, LookupActivity.class );
intent.putExtra( LookupActivity.WORDS, words );
intent.putExtra( LookupActivity.LANG, m_gi.dictLang );
m_words = words;
showDialog( DLG_LOOKUP );
}
startActivity( intent );
private void setupPasswdVars()
{
String fmt = getString( R.string.msg_ask_password );
m_dlgTitleStr = String.format( fmt, m_pwdName );
m_passwdLyt = (LinearLayout)Utils.inflate( BoardActivity.this,
R.layout.passwd_view );
m_passwdEdit = (EditText)m_passwdLyt.findViewById( R.id.edit );
}
} // class BoardActivity

View file

@ -632,24 +632,27 @@ public class GameConfig extends XWActivity
boolean canDelete = names.length > 2
|| (m_notNetworkedGame && names.length > 1);
LayoutInflater factory = LayoutInflater.from(this);
View.OnClickListener lstnr = new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_whichPlayer = ((XWListItem)view).getPosition();
showDialog( PLAYER_EDIT );
}
};
for ( int ii = 0; ii < names.length; ++ii ) {
final XWListItem view
= (XWListItem)factory.inflate( R.layout.list_item, null );
view.setPosition( ii );
view.setText( names[ii] );
view.setGravity( Gravity.CENTER );
if ( m_gi.players[ii].isLocal ) {
view.setComment( m_gi.dictName(ii) );
}
if ( canDelete ) {
view.setDeleteCallback( this );
}
view.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick( View view ) {
m_whichPlayer = ((XWListItem)view).getPosition();
showDialog( PLAYER_EDIT );
}
} );
view.setOnClickListener( lstnr );
m_playerLayout.addView( view );
view.setEnabled( !m_isLocked );
@ -675,20 +678,6 @@ public class GameConfig extends XWActivity
adjustPlayersLabel();
} // loadPlayersList
private String[] buildListWithBrowse( String[] input )
{
Arrays.sort( input );
int browsePosn = input.length;
String[] result = new String[browsePosn+1];
result[browsePosn] = getString( R.string.download_dicts );
for ( int ii = 0; ii < browsePosn; ++ii ) {
String lang = input[ii];
result[ii] = lang;
}
return result;
}
private void configDictSpinner( final Dialog dialog, LocalPlayer lp )
{
Spinner dictsSpinner =
@ -738,6 +727,7 @@ public class GameConfig extends XWActivity
m_gi.setLang( DictLangCache.
getLangLangCode( GameConfig.this,
chosen ) );
loadPlayersList();
}
}

View file

@ -20,8 +20,9 @@
package org.eehouse.android.xw4;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
@ -31,30 +32,25 @@ import android.view.Window;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.app.AlertDialog;
import java.util.ArrayList;
import android.util.AttributeSet;
import junit.framework.Assert;
public class LookupActivity extends XWListActivity
public class LookupView extends LinearLayout
implements View.OnClickListener,
AdapterView.OnItemClickListener {
public static final String WORDS = "WORDS";
public static final String LANG = "LANG";
public static final String STATE = "STATE";
public static final String WORDINDEX = "WORDINDEX";
public static final String URLINDEX = "URLINDEX";
AdapterView.OnItemClickListener,
DialogInterface.OnDismissListener {
private static final int STATE_DONE = 0;
private static final int STATE_WORDS = 1;
private static final int STATE_URLS = 2;
private static final int STATE_LOOKUP = 3;
private static final int LOOKUP_ACTION = 1;
private static String[] s_langCodes;
private static String[] s_lookupNames;
private static String[] s_lookupUrls;
@ -71,26 +67,28 @@ public class LookupActivity extends XWListActivity
private ArrayAdapter<String> m_wordsAdapter;
private Button m_doneButton;
private TextView m_summary;
private Dialog m_dialog;
private Context m_context;
private int m_dlgId;
private ListView m_list;
@Override
protected void onCreate( Bundle savedInstanceState )
public LookupView( Context cx, AttributeSet as ) {
super( cx, as );
m_context = cx;
}
public void setWords( String[] words, int lang )
{
super.onCreate( savedInstanceState );
m_words = words;
setLang( lang );
requestWindowFeature( Window.FEATURE_NO_TITLE );
m_state = STATE_DONE;
adjustState( 1 );
Intent intent = getIntent();
m_words = intent.getStringArrayExtra( WORDS );
m_lang = intent.getIntExtra( LANG, -1 );
setLang( m_lang );
getBundledData( savedInstanceState );
setContentView( R.layout.lookup );
m_wordsAdapter = new ArrayAdapter<String>( this, LIST_LAYOUT,
m_wordsAdapter = new ArrayAdapter<String>( m_context, LIST_LAYOUT,
m_words );
getListView().setOnItemClickListener( this );
m_list = (ListView)findViewById( R.id.list );
m_list.setOnItemClickListener( this );
m_doneButton = (Button)findViewById( R.id.button_done );
m_doneButton.setOnClickListener( this );
@ -99,6 +97,13 @@ public class LookupActivity extends XWListActivity
switchState();
}
public void setDialog( Dialog dialog, int id )
{
m_dialog = dialog;
m_dlgId = id;
m_dialog.setOnDismissListener( this );
}
/* View.OnClickListener -- just the Done button */
public void onClick( View view )
{
@ -119,38 +124,10 @@ public class LookupActivity extends XWListActivity
switchState( 1 );
}
@Override
protected void onSaveInstanceState( Bundle outState )
/* DialogInterface.OnDismissListener interface */
public void onDismiss( DialogInterface di )
{
super.onSaveInstanceState( outState );
outState.putInt( STATE, m_state );
outState.putInt( WORDINDEX, m_wordIndex );
outState.putInt( URLINDEX, m_urlIndex );
}
//////////////////////////////////////////////////
// DlgDelegate.DlgClickNotify interface
//////////////////////////////////////////////////
@Override
public void dlgButtonClicked( int id, int which )
{
if ( LOOKUP_ACTION == id
&& AlertDialog.BUTTON_POSITIVE == which ) {
lookupWord( m_words[m_wordIndex], s_lookupUrls[m_urlIndex] );
switchState( -1 );
}
}
private void getBundledData( Bundle bundle )
{
if ( null == bundle ) {
m_state = STATE_DONE;
adjustState( 1 );
} else {
m_state = bundle.getInt( STATE );
m_wordIndex = bundle.getInt( WORDINDEX );
m_urlIndex = bundle.getInt( URLINDEX );
}
m_dialog.getOwnerActivity().removeDialog( m_dlgId );
}
private void adjustState( int incr )
@ -180,28 +157,23 @@ public class LookupActivity extends XWListActivity
{
switch( m_state ) {
case STATE_DONE:
finish();
m_dialog.dismiss();
break;
case STATE_WORDS:
getListView().setAdapter( m_wordsAdapter );
m_list.setAdapter( m_wordsAdapter );
setSummary( R.string.title_lookup );
m_doneButton.setText( R.string.button_done );
break;
case STATE_URLS:
getListView().setAdapter( s_urlsAdapter );
m_list.setAdapter( s_urlsAdapter );
setSummary( m_words[m_wordIndex] );
String txt = Utils.format( this, R.string.button_donef,
String txt = Utils.format( m_context, R.string.button_donef,
m_words[m_wordIndex] );
m_doneButton.setText( txt );
break;
case STATE_LOOKUP:
if ( 1 >= s_lookupUrls.length ) {
showNotAgainDlgThen( R.string.not_again_needUrlsForLang,
R.string.key_na_needUrlsForLang,
LOOKUP_ACTION );
} else {
dlgButtonClicked( LOOKUP_ACTION, AlertDialog.BUTTON_POSITIVE );
}
lookupWord( m_words[m_wordIndex], s_lookupUrls[m_urlIndex] );
switchState( -1 );
break;
default:
Assert.fail();
@ -221,7 +193,7 @@ public class LookupActivity extends XWListActivity
intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK );
try {
startActivity( intent );
m_context.startActivity( intent );
} catch ( android.content.ActivityNotFoundException anfe ) {
Utils.logf( "%s", anfe.toString() );
}
@ -248,7 +220,7 @@ public class LookupActivity extends XWListActivity
}
s_lookupNames = tmpNames.toArray( new String[tmpNames.size()] );
s_lookupUrls = tmpUrls.toArray( new String[tmpUrls.size()] );
s_urlsAdapter = new ArrayAdapter<String>( this, LIST_LAYOUT,
s_urlsAdapter = new ArrayAdapter<String>( m_context, LIST_LAYOUT,
s_lookupNames );
s_lang = lang;
} // initLookup
@ -256,13 +228,12 @@ public class LookupActivity extends XWListActivity
private void setSummary( int id )
{
m_summary.setText( getString( id ) );
m_summary.setText( m_context.getString( id ) );
}
private void setSummary( String word )
{
String title = Utils.format( this, R.string.pick_url_titlef, word );
String title = Utils.format( m_context, R.string.pick_url_titlef, word );
m_summary.setText( title );
}
}

View file

@ -303,6 +303,12 @@ public class CurGameInfo {
return dname;
}
public String dictName( int indx )
{
LocalPlayer lp = players[indx];
return dictName( lp );
}
public boolean addPlayer()
{
boolean added = nPlayers < MAX_NUM_PLAYERS;

View file

@ -77,7 +77,6 @@ public class JNIThread extends Thread {
CMD_RESEND,
CMD_HISTORY,
CMD_FINAL,
CMD_WORDS,
CMD_ENDGAME,
CMD_POST_OVER,
CMD_SENDCHAT,
@ -493,13 +492,6 @@ public class JNIThread extends Thread {
}
break;
case CMD_WORDS:
int nMoves = ((Integer)args[0]).intValue();
String words = XwJNI.model_getWordsPlayed( m_jniGamePtr,
nMoves );
Message.obtain( m_handler, GOT_WORDS, words ).sendToTarget();
break;
case CMD_ENDGAME:
XwJNI.server_endGame( m_jniGamePtr );
draw = true;

View file

@ -49,6 +49,7 @@ public interface UtilCtxt {
void bonusSquareHeld( int bonus );
void playerScoreHeld( int player );
void cellSquareHeld( String words );
static final int STRD_ROBOT_TRADED = 1;
static final int STR_ROBOT_MOVED = 2;

View file

@ -91,6 +91,10 @@ public class UtilCtxtImpl implements UtilCtxt {
{
}
public void cellSquareHeld( String words )
{
}
public String getUserString( int stringCode )
{
int id = 0;

View file

@ -211,9 +211,6 @@ public class XwJNI {
public static native int model_getNMoves( int gamePtr );
public static native String model_getPlayersLastScore( int gamePtr,
int player );
public static native String model_getWordsPlayed( int gamePtr,
int nTurns );
// Server
public static native void server_reset( int gamePtr );
public static native void server_handleUndo( int gamePtr );

View file

@ -726,7 +726,12 @@ hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType )
#endif
static XP_Bool
warnBadWords( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
warnBadWords( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei),
XP_U16 XP_UNUSED(start), XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
XP_Bool ok = XP_TRUE;
if ( !isLegal ) {
@ -965,15 +970,37 @@ timerFiredForPen( BoardCtxt* board )
draw = dragDropSetAdd( board );
#endif
} else {
XWBonusType bonus;
bonus = util_getSquareBonus( board->util, board->model,
col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw, (XWMiniTextType)bonus );
#else
util_bonusSquareHeld( board->util, bonus );
XP_Bool listWords = XP_FALSE;
#ifdef XWFEATURE_BOARDWORDS
XP_U16 modelCol, modelRow;
flipIf( board, col, row, &modelCol, &modelRow );
listWords = model_getTile( board->model, modelCol, modelRow,
XP_TRUE, board->selPlayer, NULL,
NULL, NULL, NULL );
if ( listWords ) {
XWStreamCtxt* stream =
mem_stream_make( MPPARM(board->mpool)
util_getVTManager(board->util), NULL,
CHANNEL_NONE,
(MemStreamCloseCallback)NULL );
model_listWordsThrough( board->model, modelCol, modelRow,
stream );
util_cellSquareHeld( board->util, stream );
stream_destroy( stream );
}
#endif
if ( !listWords ) {
XWBonusType bonus;
bonus = util_getSquareBonus( board->util, board->model,
col, row );
if ( bonus != BONUS_NONE ) {
#ifdef XWFEATURE_MINIWIN
text = draw_getMiniWText( board->draw,
(XWMiniTextType)bonus );
#else
util_bonusSquareHeld( board->util, bonus );
#endif
}
}
}
board->penTimerFired = XP_TRUE;

View file

@ -75,7 +75,11 @@ static void loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version,
PlayerCtxt* pc );
static void writePlayerCtxt( XWStreamCtxt* stream, PlayerCtxt* pc );
static XP_U16 model_getRecentPassCount( ModelCtxt* model );
static XP_Bool recordWord( const XP_UCHAR* word, XP_Bool isLegal, void* clsur );
static XP_Bool recordWord( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* movei, XP_U16 start, XP_U16 end,
#endif
void* clsur );
/*****************************************************************************
*
@ -1948,7 +1952,11 @@ typedef struct _FirstWordData {
} FirstWordData;
static XP_Bool
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
getFirstWord( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start), XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
if ( isLegal ) {
FirstWordData* data = (FirstWordData*)closure;
@ -2034,16 +2042,26 @@ model_recentPassCountOk( ModelCtxt* model )
return count < okCount;
}
static XP_Bool
recordWord( const XP_UCHAR* word, XP_Bool XP_UNUSED(isLegal), void* closure )
static void
appendWithCR( XWStreamCtxt* stream, const XP_UCHAR* word, XP_U16* counter )
{
RecordWordsInfo* info = (RecordWordsInfo*)closure;
XWStreamCtxt* stream = info->stream;
XP_LOGF( "%s(%s)", __func__, word );
if ( 0 < info->nWords++ ) {
if ( 0 < (*counter)++ ) {
stream_putU8( stream, '\n' );
}
stream_catString( stream, word );
}
static XP_Bool
recordWord( const XP_UCHAR* word, XP_Bool XP_UNUSED(isLegal),
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start),
XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
RecordWordsInfo* info = (RecordWordsInfo*)closure;
appendWithCR( info->stream, word, &info->nWords );
return XP_TRUE;
}
@ -2057,32 +2075,63 @@ model_initWordCounter( ModelCtxt* model, XWStreamCtxt* stream )
return &model->vol.wni;
}
#ifdef XWFEATURE_BOARDWORDS
typedef struct _ListWordsThroughInfo {
XWStreamCtxt* stream;
XP_U16 col, row;
XP_U16 nWords;
} ListWordsThroughInfo;
static XP_Bool
listWordsThrough( const XP_UCHAR* word, XP_Bool XP_UNUSED(isLegal),
const MoveInfo* movei, XP_U16 start, XP_U16 end,
void* closure )
{
ListWordsThroughInfo* info = (ListWordsThroughInfo*)closure;
XP_Bool contained = XP_FALSE;
if ( movei->isHorizontal && movei->commonCoord == info->row ) {
contained = start <= info->col && end >= info->col;
} else if ( !movei->isHorizontal && movei->commonCoord == info->col ) {
contained = start <= info->row && end >= info->row;
}
if ( contained ) {
appendWithCR( info->stream, word, &info->nWords );
}
return XP_TRUE;
}
/* List every word played that includes the tile on {col,row}.
*
* How? Undo backwards until we find the move that placed that tile.*/
void
model_getWordsPlayed( ModelCtxt* model, XP_U16 nTurns, XWStreamCtxt* stream )
model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row,
XWStreamCtxt* stream )
{
XP_ASSERT( !!stream );
StackCtxt* stack = model->vol.stack;
StackCtxt* tmpStack = stack_copy( stack );
XP_U16 nPlayers = model->nPlayers;
XP_U16 nEntries = stack_getNEntries( stack );
nEntries -= nPlayers; /* skip assignments */
if ( nTurns > nEntries ) {
nTurns = nEntries;
}
XP_U16 nEntries = stack_getNEntries( stack ) - nPlayers; /* skip assignments */
if ( model_undoLatestMoves( model, NULL, nTurns, NULL, NULL ) ) {
WordNotifierInfo* ni = model_initWordCounter( model, stream );
if ( model_undoLatestMoves( model, NULL, nEntries, NULL, NULL ) ) {
ListWordsThroughInfo lwtInfo = { .stream = stream, .col = col,
.row = row, .nWords = 0,
};
WordNotifierInfo ni = { .proc = listWordsThrough, .closure = &lwtInfo };
/* Now push the undone moves back into the model one at a time.
recordWord() will add each played word to the stream as it's
scored */
buildModelFromStack( model, tmpStack, XP_TRUE,
nEntries - nTurns + nPlayers,/* skip assignments */
(XWStreamCtxt*)NULL, ni, (MovePrintFuncPre)NULL,
buildModelFromStack( model, tmpStack, XP_TRUE, nPlayers,
(XWStreamCtxt*)NULL, &ni, (MovePrintFuncPre)NULL,
(MovePrintFuncPost)NULL, NULL );
}
stack_destroy( tmpStack );
}
#endif
XP_Bool
model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,

View file

@ -239,6 +239,10 @@ void model_countAllTrayTiles( ModelCtxt* model, XP_U16* counts,
/********************* scoring ********************/
typedef XP_Bool (*WordNotifierProc)( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* movei, XP_U16 start,
XP_U16 end,
#endif
void* closure );
typedef struct WordNotifierInfo {
WordNotifierProc proc;
@ -252,8 +256,10 @@ XP_S16 model_getPlayerScore( ModelCtxt* model, XP_S16 player );
XP_Bool model_getPlayersLastScore( ModelCtxt* model, XP_S16 player,
XP_UCHAR* expl, XP_U16* explLen );
void model_getWordsPlayed( ModelCtxt* model, XP_U16 nTurns,
XWStreamCtxt* stream );
#ifdef XWFEATURE_BOARDWORDS
void model_listWordsThrough( ModelCtxt* model, XP_U16 col, XP_U16 row,
XWStreamCtxt* stream );
#endif
/* Have there been too many passes (so game should end)? */
XP_Bool model_recentPassCountOk( ModelCtxt* model );

View file

@ -40,9 +40,9 @@ static XP_U16 find_start( const ModelCtxt* model, XP_U16 col, XP_U16 row,
static XP_S16 checkScoreMove( ModelCtxt* model, XP_S16 turn,
EngineCtxt* engine, XWStreamCtxt* stream,
XP_Bool silent, WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn, MoveInfo* movei,
EngineCtxt* engine, XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo );
static XP_U16 scoreWord( const ModelCtxt* model, XP_U16 turn,
const MoveInfo* movei, EngineCtxt* engine,
XWStreamCtxt* stream, WordNotifierInfo* notifyInfo );
/* for formatting when caller wants an explanation of the score. These live
in separate function called only when stream != NULL so that they'll have
@ -553,7 +553,7 @@ tile_multiplier( const ModelCtxt* model, XP_U16 col, XP_U16 row )
static XP_U16
scoreWord( const ModelCtxt* model, XP_U16 turn,
MoveInfo* movei, /* new tiles */
const MoveInfo* movei, /* new tiles */
EngineCtxt* engine,/* for crosswise caching */
XWStreamCtxt* stream,
WordNotifierInfo* notifyInfo )
@ -567,7 +567,7 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
XP_U16 start, end;
XP_U16* incr;
XP_U16 col, row;
MoveInfoTile* tiles = movei->tiles;
const MoveInfoTile* tiles = movei->tiles;
XP_U16 firstCoord = tiles->varCoord;
DictionaryCtxt* dict = model_getPlayerDict( model, turn );
@ -671,7 +671,11 @@ scoreWord( const ModelCtxt* model, XP_U16 turn,
XP_UCHAR buf[(MAX_ROWS*2)+1];
dict_tilesToString( dict, checkWordBuf, len, buf,
sizeof(buf) );
(void)(*notifyInfo->proc)( buf, legal, notifyInfo->closure );
(void)(*notifyInfo->proc)( buf, legal,
#ifdef XWFEATURE_BOARDWORDS
movei, start, end,
#endif
notifyInfo->closure );
}
if ( !!stream ) {

View file

@ -212,6 +212,7 @@ pool_removeTiles( PoolContext* pool, TrayTileSet* tiles )
--pool->lettersLeft[tile];
--pool->numTilesLeft;
}
XP_LOGF( "%s: %d tiles left in pool", __func__, pool->numTilesLeft );
} /* pool_removeTiles */
XP_U16

View file

@ -1740,7 +1740,12 @@ server_setGameOverListener( ServerCtxt* server, GameOverListener gol,
} /* server_setGameOverListener */
static XP_Bool
storeBadWords( const XP_UCHAR* word, XP_Bool isLegal, void* closure )
storeBadWords( const XP_UCHAR* word, XP_Bool isLegal,
#ifdef XWFEATURE_BOARDWORDS
const MoveInfo* XP_UNUSED(movei), XP_U16 XP_UNUSED(start),
XP_U16 XP_UNUSED(end),
#endif
void* closure )
{
if ( !isLegal ) {
ServerCtxt* server = (ServerCtxt*)closure;

View file

@ -162,6 +162,9 @@ typedef struct UtilVtable {
void (*m_util_bonusSquareHeld)( XW_UtilCtxt* uc, XWBonusType bonus );
void (*m_util_playerScoreHeld)( XW_UtilCtxt* uc, XP_U16 player );
#endif
#ifdef XWFEATURE_BOARDWORDS
void (*m_util_cellSquareHeld)( XW_UtilCtxt* uc, XWStreamCtxt* words );
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
void (*m_util_addrChange)( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
@ -271,7 +274,10 @@ struct XW_UtilCtxt {
# define util_playerScoreHeld( uc, player ) \
(uc)->vtable->m_util_playerScoreHeld( (uc), (player) )
#endif
#ifdef XWFEATURE_BOARDWORDS
#define util_cellSquareHeld(uc, s) \
(uc)->vtable->m_util_cellSquareHeld( (uc), (s) )
#endif
#ifndef XWFEATURE_STANDALONE_ONLY
# define util_addrChange( uc, addro, addrn ) \
(uc)->vtable->m_util_addrChange((uc), (addro), (addrn))

View file

@ -38,6 +38,7 @@ ifdef CURSES_SMALL_SCREEN
DO_CURSES += -DCURSES_SMALL_SCREEN
endif
DO_GTK = -DPLATFORM_GTK
DO_GTK += -DXWFEATURE_BOARDWORDS
# DO_GTK += -DUSE_CAIRO
# uncomment for standalone build

View file

@ -1477,22 +1477,15 @@ cancelTimer( GtkAppGlobals* globals, XWTimerReason why )
} /* cancelTimer */
static gint
pentimer_idle_func( gpointer data )
pen_timer_func( gpointer data )
{
GtkAppGlobals* globals = (GtkAppGlobals*)data;
struct timeval tv;
XP_Bool callAgain = XP_TRUE;
gettimeofday( &tv, NULL );
if ( linuxFireTimer( &globals->cGlobals, TIMER_PENDOWN ) ) {
board_draw( globals->cGlobals.game.board );
}
if ( (tv.tv_usec - globals->penTv.tv_usec) >= globals->penTimerInterval) {
if ( linuxFireTimer( &globals->cGlobals, TIMER_PENDOWN ) ) {
board_draw( globals->cGlobals.game.board );
}
callAgain = XP_FALSE;
}
return callAgain;
return XP_FALSE;
} /* pentimer_idle_func */
static gint
@ -1546,11 +1539,10 @@ gtk_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why,
cancelTimer( globals, why );
if ( why == TIMER_PENDOWN ) {
/* half a second */
globals->penTimerInterval = 50 * 10000;
(void)gettimeofday( &globals->penTv, NULL );
newSrc = g_idle_add( pentimer_idle_func, globals );
if ( 0 != globals->timerSources[why-1] ) {
g_source_remove( globals->timerSources[why-1] );
}
newSrc = g_timeout_add( 1000, pen_timer_func, globals );
} else if ( why == TIMER_TIMERTICK ) {
/* one second */
globals->scoreTimerInterval = 100 * 10000;
@ -1718,15 +1710,6 @@ gtk_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
#if 1
XP_USE( player );
XWStreamCtxt* stream =
mem_stream_make( MEMPOOL globals->cGlobals.params->vtMgr, globals,
CHANNEL_NONE, catOnClose );
(void)model_getWordsPlayed( globals->cGlobals.game.model, 1000, stream );
stream_destroy( stream );
#else
XP_UCHAR scoreExpl[48];
XP_U16 explLen = sizeof(scoreExpl);
@ -1734,7 +1717,15 @@ gtk_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player )
player, scoreExpl, &explLen ) ) {
XP_LOGF( "got: %s", scoreExpl );
}
}
#endif
#ifdef XWFEATURE_BOARDWORDS
static void
gtk_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words )
{
XP_USE( uc );
XP_USE( words );
}
#endif
@ -1960,6 +1951,9 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_bonusSquareHeld = gtk_util_bonusSquareHeld;
util->vtable->m_util_playerScoreHeld = gtk_util_playerScoreHeld;
#endif
#ifdef XWFEATURE_BOARDWORDS
util->vtable->m_util_cellSquareHeld = gtk_util_cellSquareHeld;
#endif
util->closure = globals;
} /* setupGtkUtilCallbacks */

View file

@ -106,8 +106,6 @@ typedef struct GtkAppGlobals {
guint idleID;
struct timeval penTv; /* for timer */
XP_U32 penTimerInterval;
struct timeval scoreTv; /* for timer */
XP_U32 scoreTimerInterval;