From 0dfa69b1b236eedb930d9f43f3efdb7d24fd37c1 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Tue, 11 Oct 2011 19:38:26 -0700 Subject: [PATCH 1/9] implement pen timer with timeout, not idle. --- xwords4/linux/gtkmain.c | 26 +++++++++----------------- xwords4/linux/gtkmain.h | 2 -- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index 01fd16e61..cda18207d 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -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; diff --git a/xwords4/linux/gtkmain.h b/xwords4/linux/gtkmain.h index 92de46fae..f99713213 100644 --- a/xwords4/linux/gtkmain.h +++ b/xwords4/linux/gtkmain.h @@ -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; From 01459285d5552f84b55ca278743569353e349b85 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Wed, 12 Oct 2011 18:37:31 -0700 Subject: [PATCH 2/9] show dict as comment beside player name in players list. And since dicts change when language does, put language choice above players list. --- .../XWords4/res/layout/game_config.xml | 23 ++++++------ .../org/eehouse/android/xw4/GameConfig.java | 36 +++++++------------ .../eehouse/android/xw4/jni/CurGameInfo.java | 6 ++++ 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/xwords4/android/XWords4/res/layout/game_config.xml b/xwords4/android/XWords4/res/layout/game_config.xml index b7d0c3dbe..f8e0744e7 100644 --- a/xwords4/android/XWords4/res/layout/game_config.xml +++ b/xwords4/android/XWords4/res/layout/game_config.xml @@ -47,6 +47,18 @@ android:layout_height="fill_parent" android:orientation="vertical"> + + + + + - - - - 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(); } } diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java index b49dc41c9..18e930bdc 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/CurGameInfo.java @@ -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; From 74499233287af7cfb78f7218f7ff6a09b7b3ee78 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Thu, 13 Oct 2011 19:10:13 -0700 Subject: [PATCH 3/9] log tiles left in pool -- makes progress of automated/test games easier to follow. --- xwords4/common/pool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xwords4/common/pool.c b/xwords4/common/pool.c index 643a4baef..b2491d418 100644 --- a/xwords4/common/pool.c +++ b/xwords4/common/pool.c @@ -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 From 0e6b4d749f7d7c15c1aec3c381e3779a90212ca1 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Thu, 13 Oct 2011 19:14:08 -0700 Subject: [PATCH 4/9] When pen held on committed tile on board, cons up list of all words played that include that tile and pass to new util_cellSquareHeld() method. In java implementation of that method, use existing lookup activity code to display list of words. Enabled on the C side by a compile-time flag in case it has problems. Right now the time spent saving a game before launching the lookup activity, and reloading it after, is pretty apparent, but that's in emulator which is slow. --- xwords4/android/XWords4/jni/Android.mk | 1 + xwords4/android/XWords4/jni/utilwrapper.c | 19 ++++ .../eehouse/android/xw4/BoardActivity.java | 12 ++- .../org/eehouse/android/xw4/jni/UtilCtxt.java | 1 + .../eehouse/android/xw4/jni/UtilCtxtImpl.java | 4 + xwords4/common/board.c | 45 +++++++-- xwords4/common/model.c | 93 +++++++++++++++++-- xwords4/common/model.h | 8 ++ xwords4/common/mscore.c | 16 ++-- xwords4/common/server.c | 7 +- xwords4/common/util.h | 8 +- xwords4/linux/Makefile | 1 + xwords4/linux/gtkmain.c | 12 +++ 13 files changed, 201 insertions(+), 26 deletions(-) diff --git a/xwords4/android/XWords4/jni/Android.mk b/xwords4/android/XWords4/jni/Android.mk index 97b046bb8..7787db2c9 100644 --- a/xwords4/android/XWords4/jni/Android.mk +++ b/xwords4/android/XWords4/jni/Android.mk @@ -23,6 +23,7 @@ local_DEFINES += \ -DDROP_BITMAPS \ -DDISABLE_EMPTYTRAY_UNDO \ -DDISABLE_TILE_SEL \ + -DXWFEATURE_BOARDWORDS \ -DNODE_CAN_4 \ -DRELAY_ROOM_DEFAULT=\"\"\ -D__LITTLE_ENDIAN \ diff --git a/xwords4/android/XWords4/jni/utilwrapper.c b/xwords4/android/XWords4/jni/utilwrapper.c index ed0bc12df..a2a1a9cef 100644 --- a/xwords4/android/XWords4/jni/utilwrapper.c +++ b/xwords4/android/XWords4/jni/utilwrapper.c @@ -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 diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index 712e947be..952920ccd 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -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 @@ -993,6 +993,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] ) { diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java index 72efae8c5..646757ce4 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxt.java @@ -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; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java index 5e2aeb418..435df4f70 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/jni/UtilCtxtImpl.java @@ -91,6 +91,10 @@ public class UtilCtxtImpl implements UtilCtxt { { } + public void cellSquareHeld( String words ) + { + } + public String getUserString( int stringCode ) { int id = 0; diff --git a/xwords4/common/board.c b/xwords4/common/board.c index 476cc61f9..b279f3fae 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -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; diff --git a/xwords4/common/model.c b/xwords4/common/model.c index 925683786..b39fd06da 100644 --- a/xwords4/common/model.c +++ b/xwords4/common/model.c @@ -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 ) { LOG_FUNC(); if ( isLegal ) { @@ -2035,16 +2043,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; } @@ -2085,6 +2103,65 @@ model_getWordsPlayed( ModelCtxt* model, XP_U16 nTurns, XWStreamCtxt* stream ) stack_destroy( tmpStack ); } +#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_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 ) - nPlayers; /* skip assignments */ + + 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, nPlayers, + (XWStreamCtxt*)NULL, &ni, (MovePrintFuncPre)NULL, + (MovePrintFuncPost)NULL, NULL ); + } + stack_destroy( tmpStack ); +} +#endif + XP_Bool model_getPlayersLastScore( ModelCtxt* model, XP_S16 player, XP_UCHAR* expl, XP_U16* explLen ) diff --git a/xwords4/common/model.h b/xwords4/common/model.h index b24b2371f..50b433166 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -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; @@ -254,6 +258,10 @@ 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 ); diff --git a/xwords4/common/mscore.c b/xwords4/common/mscore.c index 6be9b12ae..012cada53 100644 --- a/xwords4/common/mscore.c +++ b/xwords4/common/mscore.c @@ -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 ) { diff --git a/xwords4/common/server.c b/xwords4/common/server.c index 24a1ea5fe..14409bdae 100644 --- a/xwords4/common/server.c +++ b/xwords4/common/server.c @@ -1734,7 +1734,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; diff --git a/xwords4/common/util.h b/xwords4/common/util.h index 4ba082f01..b1da52012 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -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)) diff --git a/xwords4/linux/Makefile b/xwords4/linux/Makefile index 9be2e4f46..b3dbcbcbd 100644 --- a/xwords4/linux/Makefile +++ b/xwords4/linux/Makefile @@ -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 diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index cda18207d..62f9780d2 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -1730,6 +1730,15 @@ gtk_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player ) } #endif +#ifdef XWFEATURE_BOARDWORDS +static void +gtk_util_cellSquareHeld( XW_UtilCtxt* uc, XWStreamCtxt* words ) +{ + XP_USE( uc ); + XP_USE( words ); +} +#endif + static void gtk_util_userError( XW_UtilCtxt* uc, UtilErrID id ) { @@ -1952,6 +1961,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 */ From 0b54b190b6084a95c3617ae9c28ac01c24d22127 Mon Sep 17 00:00:00 2001 From: Eric House Date: Fri, 14 Oct 2011 18:39:39 -0700 Subject: [PATCH 5/9] make lookup dialog a mere dialog rather than an activity to fix too-slow transitions to and from it. Works by keeping code in separate custom view and not setting buttons or anything else on the dialog. --- xwords4/android/XWords4/AndroidManifest.xml | 5 - xwords4/android/XWords4/res/layout/lookup.xml | 15 +-- .../eehouse/android/xw4/BoardActivity.java | 19 ++- .../eehouse/android/xw4/LookupActivity.java | 117 +++++++----------- 4 files changed, 65 insertions(+), 91 deletions(-) diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml index 74a1e6aac..61ae73545 100644 --- a/xwords4/android/XWords4/AndroidManifest.xml +++ b/xwords4/android/XWords4/AndroidManifest.xml @@ -83,11 +83,6 @@ > - - diff --git a/xwords4/android/XWords4/res/layout/lookup.xml b/xwords4/android/XWords4/res/layout/lookup.xml index cb0080a26..7e9ad2b71 100644 --- a/xwords4/android/XWords4/res/layout/lookup.xml +++ b/xwords4/android/XWords4/res/layout/lookup.xml @@ -6,11 +6,12 @@ - + - - + diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index 952920ccd..af3713795 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -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 @@ -326,6 +327,15 @@ public class BoardActivity extends XWActivity } break; + case DLG_LOOKUP: + LookupActivity view = (LookupActivity)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; @@ -1049,7 +1059,7 @@ public class BoardActivity extends XWActivity if ( null == m_passwdEdit ) { m_passwdLyt = (LinearLayout)Utils.inflate( BoardActivity.this, - R.layout.passwd_view ); + R.layout.passwd_view ); m_passwdEdit = (EditText)m_passwdLyt.findViewById( R.id.edit ); } waitBlockingDialog( ASK_PASSWORD_BLK, 0 ); @@ -1582,11 +1592,8 @@ 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 ); - - startActivity( intent ); + m_words = words; + showDialog( DLG_LOOKUP ); } } // class BoardActivity diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java index aa22916c3..276a64332 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java @@ -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 LookupActivity 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 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 LookupActivity( 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( this, LIST_LAYOUT, + m_wordsAdapter = new ArrayAdapter( 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( this, LIST_LAYOUT, + s_urlsAdapter = new ArrayAdapter( 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 ); } - } From e848b150b5950b15261f511a7ceb120d8eb2acd6 Mon Sep 17 00:00:00 2001 From: Eric House Date: Fri, 14 Oct 2011 18:45:47 -0700 Subject: [PATCH 6/9] rename LookupActivity->LookupView since it's not an Activity any more. --- xwords4/android/XWords4/res/layout/lookup.xml | 4 +- .../eehouse/android/xw4/BoardActivity.java | 2 +- .../org/eehouse/android/xw4/LookupView.java | 239 ++++++++++++++++++ 3 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java diff --git a/xwords4/android/XWords4/res/layout/lookup.xml b/xwords4/android/XWords4/res/layout/lookup.xml index 7e9ad2b71..f5fd8e30b 100644 --- a/xwords4/android/XWords4/res/layout/lookup.xml +++ b/xwords4/android/XWords4/res/layout/lookup.xml @@ -6,7 +6,7 @@ - - + diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index af3713795..e5144cef4 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -328,7 +328,7 @@ public class BoardActivity extends XWActivity break; case DLG_LOOKUP: - LookupActivity view = (LookupActivity)Utils.inflate( this, R.layout.lookup ); + LookupView view = (LookupView)Utils.inflate( this, R.layout.lookup ); dialog = new AlertDialog.Builder( this ) .setView( view ) .create(); diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java new file mode 100644 index 000000000..98106f32b --- /dev/null +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupView.java @@ -0,0 +1,239 @@ +/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ +/* + * Copyright 2009-2011 by Eric House (xwords@eehouse.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. + */ + +package org.eehouse.android.xw4; + +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; +import android.os.Bundle; +import android.view.View; +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 LookupView extends LinearLayout + implements View.OnClickListener, + 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 String[] s_langCodes; + private static String[] s_lookupNames; + private static String[] s_lookupUrls; + private static ArrayAdapter s_urlsAdapter; + private static final int LIST_LAYOUT = android.R.layout.simple_list_item_1; + + private static int s_lang = -1; + + private String[] m_words; + private static int m_lang; + private int m_wordIndex = 0; + private int m_urlIndex = 0; + private int m_state; + private ArrayAdapter 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; + + public LookupView( Context cx, AttributeSet as ) { + super( cx, as ); + m_context = cx; + } + + public void setWords( String[] words, int lang ) + { + m_words = words; + setLang( lang ); + + m_state = STATE_DONE; + adjustState( 1 ); + + m_wordsAdapter = new ArrayAdapter( m_context, LIST_LAYOUT, + m_words ); + m_list = (ListView)findViewById( R.id.list ); + m_list.setOnItemClickListener( this ); + + m_doneButton = (Button)findViewById( R.id.button_done ); + m_doneButton.setOnClickListener( this ); + m_summary = (TextView)findViewById( R.id.summary ); + + 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 ) + { + switchState( -1 ); + } + + /* AdapterView.OnItemClickListener */ + public void onItemClick( AdapterView parent, View view, + int position, long id ) + { + if ( STATE_WORDS == m_state ) { + m_wordIndex = position; + } else if ( STATE_URLS == m_state ) { + m_urlIndex = position; + } else { + Assert.fail(); + } + switchState( 1 ); + } + + /* DialogInterface.OnDismissListener interface */ + public void onDismiss( DialogInterface di ) + { + m_dialog.getOwnerActivity().removeDialog( m_dlgId ); + } + + private void adjustState( int incr ) + { + m_state += incr; + for ( ; ; ) { + int curState = m_state; + if ( STATE_WORDS == m_state && 1 >= m_words.length ) { + m_state += incr; + } + if ( STATE_URLS == m_state && 1 >= s_lookupUrls.length ) { + m_state += incr; + } + if ( m_state == curState ) { + break; + } + } + } + + private void switchState( int incr ) + { + adjustState( incr ); + switchState(); + } + + private void switchState() + { + switch( m_state ) { + case STATE_DONE: + m_dialog.dismiss(); + break; + case STATE_WORDS: + m_list.setAdapter( m_wordsAdapter ); + setSummary( R.string.title_lookup ); + m_doneButton.setText( R.string.button_done ); + break; + case STATE_URLS: + m_list.setAdapter( s_urlsAdapter ); + setSummary( m_words[m_wordIndex] ); + String txt = Utils.format( m_context, R.string.button_donef, + m_words[m_wordIndex] ); + m_doneButton.setText( txt ); + break; + case STATE_LOOKUP: + lookupWord( m_words[m_wordIndex], s_lookupUrls[m_urlIndex] ); + switchState( -1 ); + break; + default: + Assert.fail(); + break; + } + } // adjustState + + private void lookupWord( String word, String fmt ) + { + if ( false ) { + Utils.logf( "skipping lookupWord(%s)", word ); + } else { + String langCode = s_langCodes[s_lang]; + String dict_url = String.format( fmt, langCode, word ); + Uri uri = Uri.parse( dict_url ); + Intent intent = new Intent( Intent.ACTION_VIEW, uri ); + intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK ); + + try { + m_context.startActivity( intent ); + } catch ( android.content.ActivityNotFoundException anfe ) { + Utils.logf( "%s", anfe.toString() ); + } + } + } // lookupWord + + public void setLang( int lang ) + { + if ( null == s_langCodes ) { + s_langCodes = getResources().getStringArray( R.array.language_codes ); + } + + if ( s_lang != lang ) { + String[] urls = getResources().getStringArray( R.array.lookup_urls ); + ArrayList tmpUrls = new ArrayList(); + ArrayList tmpNames = new ArrayList(); + String langCode = String.format( ":%s:", s_langCodes[lang] ); + for ( int ii = 0; ii < urls.length; ii += 3 ) { + String codes = urls[ii+1]; + if ( 0 == codes.length() || codes.contains( langCode ) ) { + tmpNames.add( urls[ii] ); + tmpUrls.add( urls[ii+2] ); + } + } + s_lookupNames = tmpNames.toArray( new String[tmpNames.size()] ); + s_lookupUrls = tmpUrls.toArray( new String[tmpUrls.size()] ); + s_urlsAdapter = new ArrayAdapter( m_context, LIST_LAYOUT, + s_lookupNames ); + s_lang = lang; + } // initLookup + } + + private void setSummary( int id ) + { + m_summary.setText( m_context.getString( id ) ); + } + + private void setSummary( String word ) + { + String title = Utils.format( m_context, R.string.pick_url_titlef, word ); + m_summary.setText( title ); + } +} From 851b2d296f8fbce9bb7186f3eb1f2261957308fc Mon Sep 17 00:00:00 2001 From: Eric House Date: Fri, 14 Oct 2011 19:05:07 -0700 Subject: [PATCH 7/9] Should have gone with last checkin: delete of file due to renaming. --- .../eehouse/android/xw4/LookupActivity.java | 239 ------------------ 1 file changed, 239 deletions(-) delete mode 100644 xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java deleted file mode 100644 index 276a64332..000000000 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/LookupActivity.java +++ /dev/null @@ -1,239 +0,0 @@ -/* -*- compile-command: "cd ../../../../../; ant install"; -*- */ -/* - * Copyright 2009-2011 by Eric House (xwords@eehouse.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. - */ - -package org.eehouse.android.xw4; - -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; -import android.os.Bundle; -import android.view.View; -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 LinearLayout - implements View.OnClickListener, - 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 String[] s_langCodes; - private static String[] s_lookupNames; - private static String[] s_lookupUrls; - private static ArrayAdapter s_urlsAdapter; - private static final int LIST_LAYOUT = android.R.layout.simple_list_item_1; - - private static int s_lang = -1; - - private String[] m_words; - private static int m_lang; - private int m_wordIndex = 0; - private int m_urlIndex = 0; - private int m_state; - private ArrayAdapter 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; - - public LookupActivity( Context cx, AttributeSet as ) { - super( cx, as ); - m_context = cx; - } - - public void setWords( String[] words, int lang ) - { - m_words = words; - setLang( lang ); - - m_state = STATE_DONE; - adjustState( 1 ); - - m_wordsAdapter = new ArrayAdapter( m_context, LIST_LAYOUT, - m_words ); - m_list = (ListView)findViewById( R.id.list ); - m_list.setOnItemClickListener( this ); - - m_doneButton = (Button)findViewById( R.id.button_done ); - m_doneButton.setOnClickListener( this ); - m_summary = (TextView)findViewById( R.id.summary ); - - 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 ) - { - switchState( -1 ); - } - - /* AdapterView.OnItemClickListener */ - public void onItemClick( AdapterView parent, View view, - int position, long id ) - { - if ( STATE_WORDS == m_state ) { - m_wordIndex = position; - } else if ( STATE_URLS == m_state ) { - m_urlIndex = position; - } else { - Assert.fail(); - } - switchState( 1 ); - } - - /* DialogInterface.OnDismissListener interface */ - public void onDismiss( DialogInterface di ) - { - m_dialog.getOwnerActivity().removeDialog( m_dlgId ); - } - - private void adjustState( int incr ) - { - m_state += incr; - for ( ; ; ) { - int curState = m_state; - if ( STATE_WORDS == m_state && 1 >= m_words.length ) { - m_state += incr; - } - if ( STATE_URLS == m_state && 1 >= s_lookupUrls.length ) { - m_state += incr; - } - if ( m_state == curState ) { - break; - } - } - } - - private void switchState( int incr ) - { - adjustState( incr ); - switchState(); - } - - private void switchState() - { - switch( m_state ) { - case STATE_DONE: - m_dialog.dismiss(); - break; - case STATE_WORDS: - m_list.setAdapter( m_wordsAdapter ); - setSummary( R.string.title_lookup ); - m_doneButton.setText( R.string.button_done ); - break; - case STATE_URLS: - m_list.setAdapter( s_urlsAdapter ); - setSummary( m_words[m_wordIndex] ); - String txt = Utils.format( m_context, R.string.button_donef, - m_words[m_wordIndex] ); - m_doneButton.setText( txt ); - break; - case STATE_LOOKUP: - lookupWord( m_words[m_wordIndex], s_lookupUrls[m_urlIndex] ); - switchState( -1 ); - break; - default: - Assert.fail(); - break; - } - } // adjustState - - private void lookupWord( String word, String fmt ) - { - if ( false ) { - Utils.logf( "skipping lookupWord(%s)", word ); - } else { - String langCode = s_langCodes[s_lang]; - String dict_url = String.format( fmt, langCode, word ); - Uri uri = Uri.parse( dict_url ); - Intent intent = new Intent( Intent.ACTION_VIEW, uri ); - intent.setFlags( Intent.FLAG_ACTIVITY_NEW_TASK ); - - try { - m_context.startActivity( intent ); - } catch ( android.content.ActivityNotFoundException anfe ) { - Utils.logf( "%s", anfe.toString() ); - } - } - } // lookupWord - - public void setLang( int lang ) - { - if ( null == s_langCodes ) { - s_langCodes = getResources().getStringArray( R.array.language_codes ); - } - - if ( s_lang != lang ) { - String[] urls = getResources().getStringArray( R.array.lookup_urls ); - ArrayList tmpUrls = new ArrayList(); - ArrayList tmpNames = new ArrayList(); - String langCode = String.format( ":%s:", s_langCodes[lang] ); - for ( int ii = 0; ii < urls.length; ii += 3 ) { - String codes = urls[ii+1]; - if ( 0 == codes.length() || codes.contains( langCode ) ) { - tmpNames.add( urls[ii] ); - tmpUrls.add( urls[ii+2] ); - } - } - s_lookupNames = tmpNames.toArray( new String[tmpNames.size()] ); - s_lookupUrls = tmpUrls.toArray( new String[tmpUrls.size()] ); - s_urlsAdapter = new ArrayAdapter( m_context, LIST_LAYOUT, - s_lookupNames ); - s_lang = lang; - } // initLookup - } - - private void setSummary( int id ) - { - m_summary.setText( m_context.getString( id ) ); - } - - private void setSummary( String word ) - { - String title = Utils.format( m_context, R.string.pick_url_titlef, word ); - m_summary.setText( title ); - } -} From 46392da205129821dec840ad71f3a93a977d5e5a Mon Sep 17 00:00:00 2001 From: Eric House Date: Fri, 14 Oct 2011 19:07:19 -0700 Subject: [PATCH 8/9] Fix crash when password dialog comes up second time: don't be cute and reuse custom views as they remember their parent and that needs to be cleared. Just recreate each time and let gc() do its job. --- .../eehouse/android/xw4/BoardActivity.java | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java index e5144cef4..0047cca71 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/BoardActivity.java @@ -96,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"; @@ -139,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; @@ -278,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 ) @@ -424,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 ) @@ -435,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 ); } } @@ -1053,15 +1060,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 @@ -1596,4 +1599,13 @@ public class BoardActivity extends XWActivity showDialog( DLG_LOOKUP ); } + 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 From 6793742f0f48a90aebef3886fcbb66b8a8ba1b34 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Fri, 14 Oct 2011 22:32:30 -0700 Subject: [PATCH 9/9] remove option to list all words played in a single lookup dialog, and supporting code in the jni/common C. --- xwords4/android/XWords4/jni/xwjni.c | 15 ---------- .../android/XWords4/res/menu/board_menu.xml | 2 -- .../eehouse/android/xw4/BoardActivity.java | 4 --- .../eehouse/android/xw4/jni/JNIThread.java | 8 ------ .../org/eehouse/android/xw4/jni/XwJNI.java | 3 -- xwords4/common/model.c | 28 ------------------- xwords4/common/model.h | 2 -- xwords4/linux/gtkmain.c | 10 ------- 8 files changed, 72 deletions(-) diff --git a/xwords4/android/XWords4/jni/xwjni.c b/xwords4/android/XWords4/jni/xwjni.c index bc83bd101..bc2bb26a6 100644 --- a/xwords4/android/XWords4/jni/xwjni.c +++ b/xwords4/android/XWords4/jni/xwjni.c @@ -1242,21 +1242,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 ) diff --git a/xwords4/android/XWords4/res/menu/board_menu.xml b/xwords4/android/XWords4/res/menu/board_menu.xml index 0e4617561..8942cca64 100644 --- a/xwords4/android/XWords4/res/menu/board_menu.xml +++ b/xwords4/android/XWords4/res/menu/board_menu.xml @@ -30,8 +30,6 @@ - vol.wni; } -void -model_getWordsPlayed( ModelCtxt* model, XP_U16 nTurns, 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; - } - - if ( model_undoLatestMoves( model, NULL, nTurns, NULL, NULL ) ) { - WordNotifierInfo* ni = model_initWordCounter( model, stream ); - /* 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, - (MovePrintFuncPost)NULL, NULL ); - } - stack_destroy( tmpStack ); -} - #ifdef XWFEATURE_BOARDWORDS - typedef struct _ListWordsThroughInfo { XWStreamCtxt* stream; XP_U16 col, row; diff --git a/xwords4/common/model.h b/xwords4/common/model.h index 50b433166..2ac3b2127 100644 --- a/xwords4/common/model.h +++ b/xwords4/common/model.h @@ -256,8 +256,6 @@ 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 ); diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index 62f9780d2..ac4f7034a 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -1710,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); @@ -1726,7 +1717,6 @@ gtk_util_playerScoreHeld( XW_UtilCtxt* uc, XP_U16 player ) player, scoreExpl, &explLen ) ) { XP_LOGF( "got: %s", scoreExpl ); } -#endif } #endif