merge with drag_n_drop branch: apply patch generated with this command on that branch: svn diff -r 2080:2087

This commit is contained in:
ehouse 2008-03-08 23:16:21 +00:00
parent 4c730be669
commit 0b1f4b8f0a
9 changed files with 605 additions and 485 deletions

View file

@ -62,6 +62,7 @@
#include "LocalizedStrIncludes.h" #include "LocalizedStrIncludes.h"
#include "boardp.h" #include "boardp.h"
#include "dragdrpp.h"
#include "dbgutil.h" #include "dbgutil.h"
#define bEND 0x62454e44 #define bEND 0x62454e44
@ -73,8 +74,6 @@ extern "C" {
/****************************** prototypes ******************************/ /****************************** prototypes ******************************/
static XP_Bool getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row, static XP_Bool getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Rect* rect); XP_Rect* rect);
static XP_Bool coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y,
XP_U16* colP, XP_U16* rowP );
static XP_Bool drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, static XP_Bool drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool skipBlanks ); XP_Bool skipBlanks );
static void figureBoardRect( BoardCtxt* board ); static void figureBoardRect( BoardCtxt* board );
@ -82,13 +81,11 @@ static void figureBoardRect( BoardCtxt* board );
static void drawBoard( BoardCtxt* board ); static void drawBoard( BoardCtxt* board );
static void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row ); static void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
static void invalCellsUnderRect( BoardCtxt* board, XP_Rect* rect ); static void invalCellsUnderRect( BoardCtxt* board, XP_Rect* rect );
static XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16 tileIndex, Tile blankFace );
static XP_Bool rectContainsRect( XP_Rect* rect1, XP_Rect* rect2 ); static XP_Bool rectContainsRect( XP_Rect* rect1, XP_Rect* rect2 );
static void boardCellChanged( void* board, XP_U16 turn, XP_U16 col, static void boardCellChanged( void* board, XP_U16 turn, XP_U16 col,
XP_U16 row, XP_Bool added ); XP_U16 row, XP_Bool added );
static void boardTileChanged( void* board, XP_U16 turn, TileBit bits ); static void boardTilesChanged( void* board, XP_U16 turn, XP_S16 index1,
XP_S16 index2 );
static void boardTurnChanged( void* board ); static void boardTurnChanged( void* board );
static void boardGameOver( void* board ); static void boardGameOver( void* board );
static void setArrow( BoardCtxt* board, XP_U16 row, XP_U16 col ); static void setArrow( BoardCtxt* board, XP_U16 row, XP_U16 col );
@ -96,8 +93,6 @@ static void setArrowFor( BoardCtxt* board, XP_U16 player, XP_U16 col,
XP_U16 row ); XP_U16 row );
static XP_Bool setArrowVisible( BoardCtxt* board, XP_Bool visible ); static XP_Bool setArrowVisible( BoardCtxt* board, XP_Bool visible );
static XP_Bool cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool inclPending );
static void makeMiniWindowForTrade( BoardCtxt* board ); static void makeMiniWindowForTrade( BoardCtxt* board );
static void makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text, static void makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
MiniWindowType winType ); MiniWindowType winType );
@ -115,8 +110,11 @@ static XP_Bool getArrow( BoardCtxt* board, XP_U16* col, XP_U16* row );
static XP_Bool setArrowVisibleFor( BoardCtxt* board, XP_U16 player, static XP_Bool setArrowVisibleFor( BoardCtxt* board, XP_U16 player,
XP_Bool visible ); XP_Bool visible );
static XP_Bool board_moveArrow( BoardCtxt* board, XP_Key cursorKey ); static XP_Bool board_moveArrow( BoardCtxt* board, XP_Key cursorKey );
static void flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row, #ifdef POINTER_SUPPORT
XP_U16* fCol, XP_U16* fRow ); static void drawDragTileIf( BoardCtxt* board );
#endif
static XP_Bool holdsPendingTile( BoardCtxt* board,
XP_U16 pencol, XP_U16 penrow );
#ifdef KEY_SUPPORT #ifdef KEY_SUPPORT
static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey, static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey,
@ -170,7 +168,7 @@ board_make( MPFORMAL ModelCtxt* model, ServerCtxt* server, DrawCtx* draw,
/* could just pass in invalCell.... PENDING(eeh) */ /* could just pass in invalCell.... PENDING(eeh) */
model_setBoardListener( model, boardCellChanged, result ); model_setBoardListener( model, boardCellChanged, result );
model_setTrayListener( model, boardTileChanged, result ); model_setTrayListener( model, boardTilesChanged, result );
server_setTurnChangeListener( server, boardTurnChanged, result ); server_setTurnChangeListener( server, boardTurnChanged, result );
server_setGameOverListener( server, boardGameOver, result ); server_setGameOverListener( server, boardGameOver, result );
@ -739,7 +737,7 @@ timerFiredForPen( BoardCtxt* board )
const XP_UCHAR* text = (XP_UCHAR*)NULL; const XP_UCHAR* text = (XP_UCHAR*)NULL;
XP_UCHAR buf[80]; XP_UCHAR buf[80];
if ( board->penDownObject == OBJ_BOARD if ( (board->penDownObject == OBJ_BOARD) && !dragDropInProgress(board)
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
&& !board->hintDragInProgress && !board->hintDragInProgress
#endif #endif
@ -958,7 +956,7 @@ board_invalAll( BoardCtxt* board )
board->scoreBoardInvalid = XP_TRUE; board->scoreBoardInvalid = XP_TRUE;
} /* board_invalAll */ } /* board_invalAll */
static void void
flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row, flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16* fCol, XP_U16* fRow ) XP_U16* fCol, XP_U16* fRow )
{ {
@ -1261,8 +1259,11 @@ drawBoard( BoardCtxt* board )
} }
} }
/* I doubt the two of these can happen at the same time */
drawTradeWindowIf( board ); drawTradeWindowIf( board );
#ifdef POINTER_SUPPORT
drawDragTileIf( board );
#endif
draw_objFinished( board->draw, OBJ_BOARD, &board->boardBounds, draw_objFinished( board->draw, OBJ_BOARD, &board->boardBounds,
dfsFor( board, OBJ_BOARD ) ); dfsFor( board, OBJ_BOARD ) );
@ -1747,10 +1748,20 @@ drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks )
XP_UCHAR* textP = (XP_UCHAR*)ch; XP_UCHAR* textP = (XP_UCHAR*)ch;
HintAtts hintAtts; HintAtts hintAtts;
CellFlags flags = CELL_NONE; CellFlags flags = CELL_NONE;
XP_Bool isOrigin;
isEmpty = !model_getTile( model, modelCol, modelRow, showPending, isEmpty = !model_getTile( model, modelCol, modelRow, showPending,
selPlayer, &tile, &isBlank, selPlayer, &tile, &isBlank,
&pending, &recent ); &pending, &recent );
if ( dragDropIsBeingDragged( board, col, row, &isOrigin ) ) {
flags |= isOrigin? CELL_DRAGSRC : CELL_DRAGCUR;
if ( isEmpty && !isOrigin ) {
dragDropTileInfo( board, &tile, &isBlank );
pending = XP_TRUE;
recent = XP_FALSE;
isEmpty = XP_FALSE;
}
}
if ( isEmpty ) { if ( isEmpty ) {
isBlank = XP_FALSE; isBlank = XP_FALSE;
@ -1779,8 +1790,7 @@ drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks )
bonus = util_getSquareBonus( board->util, model, col, row ); bonus = util_getSquareBonus( board->util, model, col, row );
hintAtts = figureHintAtts( board, col, row ); hintAtts = figureHintAtts( board, col, row );
if ( isEmpty && (col==board->star_row) if ( (col==board->star_row) && (row==board->star_row) ) {
&& (row==board->star_row ) ) {
flags |= CELL_ISSTAR; flags |= CELL_ISSTAR;
} }
if ( invert ) { if ( invert ) {
@ -1835,7 +1845,7 @@ figureBoardRect( BoardCtxt* board )
} }
} /* figureBoardRect */ } /* figureBoardRect */
static XP_Bool XP_Bool
coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP, XP_U16* rowP ) coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP, XP_U16* rowP )
{ {
XP_U16 col, row, max; XP_U16 col, row, max;
@ -1913,7 +1923,7 @@ invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
} /* invalCell */ } /* invalCell */
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV #if defined POINTER_SUPPORT || defined KEYBOARD_NAV
static XP_Bool XP_Bool
pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y, BoardObjectType* wp ) pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y, BoardObjectType* wp )
{ {
XP_Bool result = XP_TRUE; XP_Bool result = XP_TRUE;
@ -2231,14 +2241,25 @@ static XP_Bool
handlePenDownOnBoard( BoardCtxt* board, XP_U16 x, XP_U16 y ) handlePenDownOnBoard( BoardCtxt* board, XP_U16 x, XP_U16 y )
{ {
XP_Bool result = XP_FALSE; XP_Bool result = XP_FALSE;
XP_U16 col, row;
/* Start a timer no matter what. After it fires we'll decide whether it's /* Start a timer no matter what. After it fires we'll decide whether it's
appropriate to handle it. No. That's too expensive */ appropriate to handle it. No. That's too expensive */
if ( TRADE_IN_PROGRESS(board) && ptOnTradeWindow( board, x, y ) ) { if ( TRADE_IN_PROGRESS(board) && ptOnTradeWindow( board, x, y ) ) {
return XP_FALSE; return XP_FALSE;
} }
util_setTimer( board->util, TIMER_PENDOWN, 0, p_board_timerFired, board ); util_setTimer( board->util, TIMER_PENDOWN, 0, p_board_timerFired, board );
/* As a first cut, you start a hint-region drag unless the cell is
occupied by a non-committed cell. */
coordToCell( board, x, y, &col, &row );
if ( (board->trayVisState == TRAY_REVEALED)
&& !board->tradeInProgress[board->selPlayer]
&& holdsPendingTile( board, col, row ) ) {
result = dragDropStart( board, OBJ_BOARD, col, row );
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
if ( board->gi->allowHintRect && board->trayVisState == TRAY_REVEALED ) { } else if ( board->gi->allowHintRect
&& (board->trayVisState == TRAY_REVEALED) ) {
result = startHintRegionDrag( board, x, y ); result = startHintRegionDrag( board, x, y );
} }
#endif #endif
@ -2329,8 +2350,9 @@ handleLikeDown( BoardCtxt* board, BoardObjectType onWhich, XP_U16 x, XP_U16 y )
case OBJ_TRAY: case OBJ_TRAY:
XP_ASSERT( board->trayVisState != TRAY_HIDDEN ); XP_ASSERT( board->trayVisState != TRAY_HIDDEN );
if ( board->trayVisState != TRAY_REVERSED ) { if ( board->trayVisState != TRAY_REVERSED
result = handlePenDownInTray( board, x, y ) || result; && !board->tradeInProgress[board->selPlayer] ) {
result = dragDropStart( board, OBJ_TRAY, x, y ) || result;
} }
break; break;
@ -2385,10 +2407,8 @@ board_handlePenMove( BoardCtxt* board, XP_U16 x, XP_U16 y )
{ {
XP_Bool result = XP_FALSE; XP_Bool result = XP_FALSE;
if ( board->tileDragState.dragInProgress ) { if ( dragDropInProgress(board) ) {
result = continueTileDrag( board, x, y ) != 0; result = dragDropContinue( board, x, y ) != 0;
} else if ( board->divDragState.dragInProgress ) {
result = continueDividerDrag( board, x, y ) != 0;
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->gi->allowHintRect } else if ( board->gi->allowHintRect
&& board->trayVisState == TRAY_REVEALED ) { && board->trayVisState == TRAY_REVEALED ) {
@ -2434,7 +2454,7 @@ moveSelTileToBoardXY( BoardCtxt* board, XP_U16 col, XP_U16 row )
return result; return result;
} /* moveSelTileToBoardXY */ } /* moveSelTileToBoardXY */
static XP_Bool XP_Bool
cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool inclPending ) cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool inclPending )
{ {
Tile tile; Tile tile;
@ -2486,41 +2506,37 @@ tryMoveArrow( BoardCtxt* board, XP_U16 col, XP_U16 row )
return result; return result;
} /* tryMoveArrow */ } /* tryMoveArrow */
/* Did I tap on a tile on the board that I have not yet committed? If so,
* return it to the tray.
*/
static XP_Bool static XP_Bool
tryReplaceTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow ) holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow )
{ {
XP_Bool result = XP_FALSE;
XP_S16 index;
XP_U16 col, row;
Tile tile; Tile tile;
XP_Bool ignore, isPending; XP_Bool ignore, isPending;
XP_U16 modcol, modrow; XP_U16 modcol, modrow;
flipIf( board, pencol, penrow, &modcol, &modrow ); flipIf( board, pencol, penrow, &modcol, &modrow );
if ( model_getTile( board->model, modcol, modrow, XP_TRUE,
board->selPlayer, &tile, &ignore, &isPending,
(XP_Bool*)NULL )
&& isPending ) {
XP_S16 count = model_getCurrentMoveCount( board->model, return model_getTile( board->model, modcol, modrow, XP_TRUE,
board->selPlayer ); board->selPlayer, &tile, &ignore, &isPending,
while ( count-- ) { (XP_Bool*)NULL )
index = count; && isPending;
model_getCurrentMoveTile( board->model, board->selPlayer, } /* holdsPendingTile */
&index, &tile, &col, &row, &ignore );
if ( col == modcol && row == modrow ) { /* Did I tap on a tile on the board that I have not yet committed? If so,
model_moveBoardToTray( board->model, board->selPlayer, * return it to the tray.
index ); */
/* the cursor should show up where the tile used to be so it's XP_Bool
easy to replace it. */ tryReplaceTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow )
setArrow( board, pencol, penrow ); {
result = XP_TRUE; XP_Bool result = XP_FALSE;
break;
} if ( holdsPendingTile( board, pencol, penrow ) ) {
} XP_U16 modcol, modrow;
flipIf( board, pencol, penrow, &modcol, &modrow );
model_moveBoardToTray( board->model, board->selPlayer,
modcol, modrow, -1 );
setArrow( board, pencol, penrow );
result = XP_TRUE;
} }
return result; return result;
} /* tryReplaceTile */ } /* tryReplaceTile */
@ -2549,7 +2565,8 @@ exitTradeMode( BoardCtxt* board )
XP_Bool XP_Bool
board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y ) board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
{ {
XP_Bool result = XP_FALSE; XP_Bool draw = XP_FALSE;
XP_Bool dragged = XP_FALSE;
BoardObjectType prevObj = board->penDownObject; BoardObjectType prevObj = board->penDownObject;
/* prevent timer from firing after pen lifted. Set now rather than later /* prevent timer from firing after pen lifted. Set now rather than later
@ -2557,19 +2574,19 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
exiting this function (which might give timer time to fire. */ exiting this function (which might give timer time to fire. */
board->penDownObject = OBJ_NONE; board->penDownObject = OBJ_NONE;
if ( board->tileDragState.dragInProgress ) { if ( dragDropInProgress(board) ) {
result = endTileDrag( board, x, y ); draw = dragDropEnd( board, x, y, &dragged );
} else if ( board->divDragState.dragInProgress ) { }
result = endDividerDrag( board, x, y ); if ( dragged ) {
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->hintDragInProgress ) { } else if ( board->hintDragInProgress ) {
XP_ASSERT( board->gi->allowHintRect ); XP_ASSERT( board->gi->allowHintRect );
result = finishHintRegionDrag( board, x, y ); draw = finishHintRegionDrag( board, x, y ) || draw;
#endif #endif
} else if ( board->penTimerFired ) { } else if ( board->penTimerFired ) {
if ( valHintMiniWindowActive( board ) ) { if ( valHintMiniWindowActive( board ) ) {
hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT ); hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT );
result = XP_TRUE; draw = XP_TRUE;
} }
/* Need to clean up if there's been any dragging happening */ /* Need to clean up if there's been any dragging happening */
board->penTimerFired = XP_FALSE; board->penTimerFired = XP_FALSE;
@ -2580,7 +2597,7 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
switch( onWhich ) { switch( onWhich ) {
case OBJ_SCORE: case OBJ_SCORE:
if ( prevObj == OBJ_SCORE ) { if ( prevObj == OBJ_SCORE ) {
result = handlePenUpScore( board, x, y ); draw = handlePenUpScore( board, x, y ) || draw;
} }
break; break;
case OBJ_BOARD: case OBJ_BOARD:
@ -2589,21 +2606,21 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
if ( TRADE_IN_PROGRESS(board) ) { if ( TRADE_IN_PROGRESS(board) ) {
if ( ptOnTradeWindow( board, x, y )) { if ( ptOnTradeWindow( board, x, y )) {
result = exitTradeMode( board ); draw = exitTradeMode( board ) || draw;
} }
} else { } else {
XP_U16 col, row; XP_U16 col, row;
coordToCell( board, board->penDownX, board->penDownY, coordToCell( board, board->penDownX, board->penDownY,
&col, &row ); &col, &row );
result = handleActionInCell( board, col, row ); draw = handleActionInCell( board, col, row ) || draw;
} }
} }
break; break;
case OBJ_TRAY: case OBJ_TRAY:
if ( board->trayVisState == TRAY_REVERSED ) { if ( board->trayVisState == TRAY_REVERSED ) {
result = askRevealTray( board ); draw = askRevealTray( board ) || draw;
} else { } else {
result = handlePenUpTray( board, x, y ); draw = handlePenUpTray( board, x, y ) || draw;
} }
break; break;
default: default:
@ -2615,7 +2632,7 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
board->hintDragInProgress = XP_FALSE; board->hintDragInProgress = XP_FALSE;
#endif #endif
return result; return draw;
} /* board_handlePenUp */ } /* board_handlePenUp */
#endif /* #ifdef POINTER_SUPPORT */ #endif /* #ifdef POINTER_SUPPORT */
@ -2914,8 +2931,6 @@ board_focusChanged( BoardCtxt* board, BoardObjectType typ, XP_Bool gained )
draw = invalFocusOwner( board ) || draw; draw = invalFocusOwner( board ) || draw;
} }
board->focussed = typ; board->focussed = typ;
XP_LOGF( "%s: set focussed to %s", __func__,
BoardObjectType_2str(typ) );
board->focusHasDived = XP_FALSE; board->focusHasDived = XP_FALSE;
draw = invalFocusOwner( board ) || draw; draw = invalFocusOwner( board ) || draw;
} else { } else {
@ -3148,8 +3163,7 @@ replaceLastTile( BoardCtxt* board )
index = -1; index = -1;
model_getCurrentMoveTile( board->model, board->selPlayer, &index, model_getCurrentMoveTile( board->model, board->selPlayer, &index,
&tile, &col, &row, &isBlank ); &tile, &col, &row, &isBlank );
model_moveBoardToTray( board->model, board->selPlayer, col, row, -1 );
model_moveBoardToTray( board->model, board->selPlayer, index );
flipIf( board, col, row, &col, &row ); flipIf( board, col, row, &col, &row );
setArrow( board, col, row ); setArrow( board, col, row );
@ -3160,9 +3174,9 @@ replaceLastTile( BoardCtxt* board )
return result; return result;
} /* replaceLastTile */ } /* replaceLastTile */
static XP_Bool XP_Bool
moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_U16 tileIndex, moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_U16 tileIndex,
Tile blankFace ) Tile blankFace )
{ {
if ( cellOccupied( board, col, row, XP_TRUE ) ) { if ( cellOccupied( board, col, row, XP_TRUE ) ) {
return XP_FALSE; return XP_FALSE;
@ -3340,13 +3354,13 @@ boardCellChanged( void* p_board, XP_U16 turn, XP_U16 modelCol, XP_U16 modelRow,
} /* boardCellChanged */ } /* boardCellChanged */
static void static void
boardTileChanged( void* p_board, XP_U16 turn, TileBit bits ) boardTilesChanged( void* p_board, XP_U16 turn, XP_S16 index1, XP_S16 index2 )
{ {
BoardCtxt* board = (BoardCtxt*)p_board; BoardCtxt* board = (BoardCtxt*)p_board;
if ( turn == board->selPlayer ) { if ( turn == board->selPlayer ) {
board_invalTrayTiles( board, bits ); invalTrayTilesBetween( board, index1, index2 );
} }
} /* boardTileChanged */ } /* boardTilesChanged */
static void static void
boardTurnChanged( void* p_board ) boardTurnChanged( void* p_board )
@ -3380,6 +3394,109 @@ boardGameOver( void* closure )
util_notifyGameOver( board->util ); util_notifyGameOver( board->util );
} /* boardGameOver */ } /* boardGameOver */
static void
forceRectToBoard( const BoardCtxt* board, XP_Rect* rect )
{
XP_Rect bounds = board->boardBounds;
if ( rect->left < bounds.left ) {
rect->left = bounds.left;
}
if ( rect->top < bounds.top ) {
rect->top = bounds.top;
}
if ( (rect->left + rect->width) > (bounds.left + bounds.width) ) {
rect->left -= (rect->left+rect->width) - (bounds.left+bounds.width);
}
if ( rect->top + rect->height > bounds.top + bounds.height ) {
rect->top -= (rect->top+rect->height) - (bounds.top+bounds.height);
}
} /* forceRectToBoard */
static void
getDragCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Rect* rectP )
{
XP_Rect rect;
XP_U16 tmp;
getCellRect( board, col, row, &rect );
tmp = rect.width;
rect.width = board->trayScaleH;
rect.left -= (rect.width - tmp) / 2;
tmp = rect.height;
rect.height = board->trayScaleV;
rect.top -= (rect.height - tmp) / 2;
*rectP = rect;
forceRectToBoard( board, rectP );
}
#ifdef POINTER_SUPPORT
static void
drawDragTileIf( BoardCtxt* board )
{
if ( dragDropInProgress( board ) ) {
XP_U16 col, row;
if ( dragDropGetBoardTile( board, &col, &row ) ) {
XP_Rect rect;
Tile tile;
XP_Bool isBlank;
XP_UCHAR buf[4];
XP_UCHAR* face;
XP_Bitmap bitmap = NULL;
XP_S16 value;
CellFlags flags;
getDragCellRect( board, col, row, &rect );
dragDropTileInfo( board, &tile, &isBlank );
face = getTileDrawInfo( board, tile, isBlank, &bitmap,
&value, buf, sizeof(buf) );
flags = CELL_DRAGCUR;
if ( isBlank ) {
flags |= CELL_ISBLANK;
}
draw_drawTileMidDrag( board->draw, &rect, face, bitmap, value,
flags );
}
}
} /* drawDragTileIf */
#endif
void
invalDragObj( BoardCtxt* board, const DragObjInfo* di )
{
if ( OBJ_BOARD == di->obj ) {
XP_Rect rect;
getDragCellRect( board, di->u.board.col, di->u.board.row, &rect );
invalCellsUnderRect( board, &rect );
} else if ( OBJ_TRAY == di->obj ) {
board_invalTrayTiles( board, 1 << di->u.tray.index );
}
} /* invalCurObj */
void
invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
const DragObjInfo* to )
{
invalDragObj( board, from );
if ( NULL != to ) {
invalDragObj( board, to );
if ( (OBJ_TRAY == from->obj) && (OBJ_TRAY == to->obj) ) {
invalTrayTilesBetween( board, from->u.tray.index,
to->u.tray.index );
} else if ( OBJ_TRAY == from->obj ) {
invalTrayTilesAbove( board, from->u.tray.index );
} else if ( OBJ_TRAY == to->obj ) {
invalTrayTilesAbove( board, to->u.tray.index );
}
}
}
#ifdef CPLUS #ifdef CPLUS
} }
#endif #endif

View file

@ -30,18 +30,29 @@
extern "C" { extern "C" {
#endif #endif
typedef struct TileDragState { typedef struct _DragObjInfo {
XP_Bool dragInProgress; BoardObjectType obj;
union {
struct {
XP_U16 col;
XP_U16 row;
} board;
struct {
XP_U16 index;
} tray;
} u;
} DragObjInfo;
XP_Bool wasHilited; typedef struct DragState {
TileBit selectionAtStart;
XP_Bool movePending;
TileBit prevIndex;
} TileDragState;
typedef struct DividerDragState {
XP_Bool dragInProgress; XP_Bool dragInProgress;
} DividerDragState; XP_Bool dividerOnly; /* special case; most other stuff ignored */
XP_Bool didMove; /* there was change during the drag; not a
tap */
XP_Bool isBlank; /* cache rather than lookup in model */
Tile tile; /* cache rather than lookup in model */
DragObjInfo start;
DragObjInfo cur;
} DragState;
typedef struct BoardArrow { /* gets flipped along with board */ typedef struct BoardArrow { /* gets flipped along with board */
XP_U8 col; XP_U8 col;
@ -146,8 +157,7 @@ struct BoardCtxt {
XP_Bool dividerInvalid; XP_Bool dividerInvalid;
XP_Bool scoreBoardInvalid; XP_Bool scoreBoardInvalid;
TileDragState tileDragState; DragState dragState;
DividerDragState divDragState;
MiniWindowStuff miniWindowStuff[2]; MiniWindowStuff miniWindowStuff[2];
XP_Bool tradingMiniWindowInvalid; XP_Bool tradingMiniWindowInvalid;
@ -182,22 +192,41 @@ struct BoardCtxt {
#define TRADE_IN_PROGRESS(b) ((b)->tradeInProgress[(b)->selPlayer]==XP_TRUE) #define TRADE_IN_PROGRESS(b) ((b)->tradeInProgress[(b)->selPlayer]==XP_TRUE)
/* tray-related functions */ /* tray-related functions */
XP_Bool handlePenDownInTray( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y ); XP_Bool handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y );
void drawTray( BoardCtxt* board ); void drawTray( BoardCtxt* board );
TileBit continueTileDrag( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool endTileDrag( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool continueDividerDrag( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool endDividerDrag( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool moveTileToArrowLoc( BoardCtxt* board, XP_U8 index ); XP_Bool moveTileToArrowLoc( BoardCtxt* board, XP_U8 index );
XP_U16 indexForBits( XP_U8 bits ); XP_U16 indexForBits( XP_U8 bits );
XP_Bool rectContainsPt( XP_Rect* rect1, XP_S16 x, XP_S16 y ); XP_Bool rectContainsPt( XP_Rect* rect1, XP_S16 x, XP_S16 y );
XP_Bool checkRevealTray( BoardCtxt* board ); XP_Bool checkRevealTray( BoardCtxt* board );
void invalTilesUnderRect( BoardCtxt* board, XP_Rect* rect );
void figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect ); void figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect );
XP_Bool rectsIntersect( const XP_Rect* rect1, const XP_Rect* rect2 ); XP_Bool rectsIntersect( const XP_Rect* rect1, const XP_Rect* rect2 );
XP_S16 pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y,
XP_Bool* onDividerP );
void board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer ); void board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer );
void flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16* fCol, XP_U16* fRow );
XP_Bool pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y,
BoardObjectType* wp );
XP_Bool coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP,
XP_U16* rowP );
XP_Bool cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool inclPending );
XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16 tileIndex, Tile blankFace );
void invalTilesUnderRect( BoardCtxt* board, XP_Rect* rect );
void invalDragObj( BoardCtxt* board, const DragObjInfo* di );
void invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
const DragObjInfo* to );
void invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex );
void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
XP_U16 tileIndex2 );
XP_Bool tryReplaceTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow );
void moveTileInTray( BoardCtxt* board, XP_U16 moveTo, XP_U16 moveFrom );
XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
XP_Bitmap* bitmap, XP_S16* value,
XP_UCHAR* buf, XP_U16 len );
XP_Bool dividerMoved( BoardCtxt* board, XP_U8 newLoc );
#ifdef KEYBOARD_NAV #ifdef KEYBOARD_NAV
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,

View file

@ -24,6 +24,7 @@ COMMONOBJDIR = ../common/$(PLATFORM)
COMMONSRC = \ COMMONSRC = \
$(COMMONDIR)/board.c \ $(COMMONDIR)/board.c \
$(COMMONDIR)/dragdrpp.c \
$(COMMONDIR)/scorebdp.c \ $(COMMONDIR)/scorebdp.c \
$(COMMONDIR)/tray.c \ $(COMMONDIR)/tray.c \
$(COMMONDIR)/draw.c \ $(COMMONDIR)/draw.c \
@ -47,6 +48,7 @@ COMMONSRC = \
COMMON1 = \ COMMON1 = \
$(COMMONOBJDIR)/board.o \ $(COMMONOBJDIR)/board.o \
$(COMMONOBJDIR)/dragdrpp.o \
$(COMMONOBJDIR)/tray.o \ $(COMMONOBJDIR)/tray.o \
$(COMMONOBJDIR)/scorebdp.o \ $(COMMONOBJDIR)/scorebdp.o \
$(COMMONOBJDIR)/draw.o \ $(COMMONOBJDIR)/draw.o \

View file

@ -37,6 +37,8 @@ typedef enum {
, CELL_ISSTAR = 0x04 , CELL_ISSTAR = 0x04
, CELL_ISCURSOR = 0x08 , CELL_ISCURSOR = 0x08
, CELL_ISEMPTY = 0x10 /* of a tray tile slot */ , CELL_ISEMPTY = 0x10 /* of a tray tile slot */
, CELL_DRAGSRC = 0x20 /* where drag originated */
, CELL_DRAGCUR = 0x40 /* where drag is now */
, CELL_ALL = 0xFF , CELL_ALL = 0xFF
} CellFlags; } CellFlags;
@ -166,6 +168,12 @@ typedef struct DrawCtxVTable {
/* at least 1 of these two will be null*/ /* at least 1 of these two will be null*/
const XP_UCHAR* text, const XP_Bitmap bitmap, const XP_UCHAR* text, const XP_Bitmap bitmap,
XP_S16 val, CellFlags flags ); XP_S16 val, CellFlags flags );
#ifdef POINTER_SUPPORT
void DRAW_VTABLE_NAME(drawTileMidDrag) ( DrawCtx* dctx, const XP_Rect* rect,
/* at least 1 of these two will be null*/
const XP_UCHAR* text, const XP_Bitmap bitmap,
XP_S16 val, CellFlags flags );
#endif
void DRAW_VTABLE_NAME(drawTileBack) ( DrawCtx* dctx, const XP_Rect* rect, void DRAW_VTABLE_NAME(drawTileBack) ( DrawCtx* dctx, const XP_Rect* rect,
CellFlags flags ); CellFlags flags );
void DRAW_VTABLE_NAME(drawTrayDivider) ( DrawCtx* dctx, const XP_Rect* rect, void DRAW_VTABLE_NAME(drawTrayDivider) ( DrawCtx* dctx, const XP_Rect* rect,
@ -254,6 +262,10 @@ struct DrawCtx {
#define draw_invertCell( dc, rect ) CALL_DRAW_NAME1(invertCell,(dc),(rect)) #define draw_invertCell( dc, rect ) CALL_DRAW_NAME1(invertCell,(dc),(rect))
#define draw_drawTile( dc, rect, text, bmp, val, hil ) \ #define draw_drawTile( dc, rect, text, bmp, val, hil ) \
CALL_DRAW_NAME5(drawTile,(dc),(rect),(text),(bmp),(val),(hil)) CALL_DRAW_NAME5(drawTile,(dc),(rect),(text),(bmp),(val),(hil))
#ifdef POINTER_SUPPORT
#define draw_drawTileMidDrag( dc, rect, text, bmp, val, hil ) \
CALL_DRAW_NAME5(drawTileMidDrag,(dc),(rect),(text),(bmp),(val),(hil))
#endif /* POINTER_SUPPORT */
#define draw_drawTileBack( dc, rect, f ) \ #define draw_drawTileBack( dc, rect, f ) \
CALL_DRAW_NAME2(drawTileBack, (dc), (rect), (f) ) CALL_DRAW_NAME2(drawTileBack, (dc), (rect), (f) )
#define draw_drawTrayDivider( dc, rect, s ) \ #define draw_drawTrayDivider( dc, rect, s ) \

View file

@ -48,7 +48,8 @@ static void decrPendingTileCountAt( ModelCtxt* model, XP_U16 col,
XP_U16 row ); XP_U16 row );
static void notifyBoardListeners( ModelCtxt* model, XP_U16 turn, static void notifyBoardListeners( ModelCtxt* model, XP_U16 turn,
XP_U16 col, XP_U16 row, XP_Bool added ); XP_U16 col, XP_U16 row, XP_Bool added );
static void notifyTrayListeners( ModelCtxt* model, XP_U16 turn, TileBit bits); static void notifyTrayListeners( ModelCtxt* model, XP_U16 turn,
XP_S16 index1, XP_S16 index2 );
static CellTile getModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row ); static CellTile getModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row );
static void setModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row, static void setModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row,
CellTile tile ); CellTile tile );
@ -874,30 +875,35 @@ model_getCurrentMoveTile( ModelCtxt* model, XP_S16 turn, XP_S16* index,
*tile = pt->tile & TILE_VALUE_MASK; *tile = pt->tile & TILE_VALUE_MASK;
} /* model_getCurrentMoveTile */ } /* model_getCurrentMoveTile */
Tile static Tile
model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index ) removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index )
{ {
PlayerCtxt* player = &model->players[turn]; PlayerCtxt* player = &model->players[turn];
Tile tile; Tile tile;
short i; short i;
TileBit bits = 0;
if ( index < 0 ) { XP_ASSERT( index < player->trayTiles.nTiles );
index = player->trayTiles.nTiles - 1;
} else {
XP_ASSERT( index < player->trayTiles.nTiles );
}
tile = player->trayTiles.tiles[index]; tile = player->trayTiles.tiles[index];
bits = 1 << index;
--player->trayTiles.nTiles; --player->trayTiles.nTiles;
for ( i = index; i < player->trayTiles.nTiles; ++i ) { for ( i = index; i < player->trayTiles.nTiles; ++i ) {
player->trayTiles.tiles[i] = player->trayTiles.tiles[i+1]; player->trayTiles.tiles[i] = player->trayTiles.tiles[i+1];
bits |= 3 << i;
} }
notifyTrayListeners( model, turn, bits ); return tile;
} /* removePlayerTile */
Tile
model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index )
{
Tile tile;
PlayerCtxt* player = &model->players[turn];
if ( index < 0 ) {
index = player->trayTiles.nTiles - 1;
}
tile = removePlayerTile( model, turn, index );
notifyTrayListeners( model, turn, index, player->trayTiles.nTiles );
return tile; return tile;
} /* model_removePlayerTile */ } /* model_removePlayerTile */
@ -1003,28 +1009,36 @@ model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row,
} /* model_moveTrayToBoard */ } /* model_moveTrayToBoard */
void void
model_moveBoardToTray( ModelCtxt* model, XP_S16 turn, XP_S16 index ) model_moveBoardToTray( ModelCtxt* model, XP_S16 turn,
XP_U16 col, XP_U16 row, XP_U16 trayOffset )
{ {
XP_S16 index;
PlayerCtxt* player; PlayerCtxt* player;
short i; short i;
PendingTile* pt; PendingTile* pt;
Tile tile; Tile tile;
player = &model->players[turn]; player = &model->players[turn];
if ( index < 0 ) { for ( pt = player->pendingTiles, index = 0;
index = player->nPending - 1; index < player->nPending;
} ++index, ++pt ) {
if ( pt->col == col && pt->row == row ) {
break;
}
}
/* may be legal to fail to find, but we'd better return now! */
XP_ASSERT( index < player->nPending );
decrPendingTileCountAt( model, col, row );
notifyBoardListeners( model, turn, col, row, XP_FALSE );
pt = &player->pendingTiles[index];
decrPendingTileCountAt( model, pt->col, pt->row );
notifyBoardListeners( model, turn, pt->col, pt->row, XP_FALSE );
tile = pt->tile; tile = pt->tile;
if ( (tile & TILE_BLANK_BIT) != 0 ) { if ( (tile & TILE_BLANK_BIT) != 0 ) {
tile = dict_getBlankTile( model->vol.dict ); tile = dict_getBlankTile( model->vol.dict );
} }
model_addPlayerTile( model, turn, -1, tile ); model_addPlayerTile( model, turn, trayOffset, tile );
--player->nPending; --player->nPending;
for ( i = index; i < player->nPending; ++i ) { for ( i = index; i < player->nPending; ++i ) {
@ -1038,6 +1052,36 @@ model_moveBoardToTray( ModelCtxt* model, XP_S16 turn, XP_S16 index )
invalidateScore( model, turn ); invalidateScore( model, turn );
} /* model_moveBoardToTray */ } /* model_moveBoardToTray */
void
model_moveTileOnBoard( ModelCtxt* model, XP_S16 turn, XP_U16 colCur,
XP_U16 rowCur, XP_U16 colNew, XP_U16 rowNew )
{
PlayerCtxt* player = &model->players[turn];
XP_S16 index = player->nPending;
while ( index-- ) {
Tile tile;
XP_U16 tcol, trow;
XP_Bool isBlank;
model_getCurrentMoveTile( model, turn, &index, &tile, &tcol, &trow,
&isBlank );
if ( colCur == tcol && rowCur == trow ) {
PendingTile* pt = &player->pendingTiles[index];
pt->col = colNew;
pt->row = rowNew;
if ( isBlank ) {
pt->tile = TILE_BLANK_BIT | askBlankTile( model, turn );
}
decrPendingTileCountAt( model, colCur, rowCur );
incrPendingTileCountAt( model, colNew, rowNew );
invalidateScore( model, turn );
break;
}
}
}
void void
model_resetCurrentTurn( ModelCtxt* model, XP_S16 whose ) model_resetCurrentTurn( ModelCtxt* model, XP_S16 whose )
{ {
@ -1047,7 +1091,10 @@ model_resetCurrentTurn( ModelCtxt* model, XP_S16 whose )
player = &model->players[whose]; player = &model->players[whose];
while ( player->nPending > 0 ) { while ( player->nPending > 0 ) {
model_moveBoardToTray( model, whose, -1 ); model_moveBoardToTray( model, whose,
player->pendingTiles[0].col,
player->pendingTiles[0].row,
-1 );
} }
} /* model_resetCurrentTurn */ } /* model_resetCurrentTurn */
@ -1104,27 +1151,13 @@ static void
putBackOtherPlayersTiles( ModelCtxt* model, XP_U16 notMyTurn, putBackOtherPlayersTiles( ModelCtxt* model, XP_U16 notMyTurn,
XP_U16 col, XP_U16 row ) XP_U16 col, XP_U16 row )
{ {
XP_S16 turn, j; XP_S16 turn;
for ( turn = 0; turn < model->nPlayers; ++turn ) { for ( turn = 0; turn < model->nPlayers; ++turn ) {
PlayerCtxt* player;
if ( turn == notMyTurn ) { if ( turn == notMyTurn ) {
continue; continue;
} }
model_moveBoardToTray( model, turn, col, row, -1 );
player = &model->players[turn];
for ( j = player->nPending-1; j >= 0; --j ) { /* backwards in case
removed */
PendingTile* pt = &player->pendingTiles[j];
if ( pt->col == col && pt->row == row ) {
/* this one needs to be put back */
model_moveBoardToTray( model, turn, j );
break; /* a player can have only one tile on a square */
}
}
} }
} /* putBackOtherPlayersTiles */ } /* putBackOtherPlayersTiles */
@ -1271,31 +1304,44 @@ model_getPlayerTiles( ModelCtxt* model, XP_S16 turn )
return (const TrayTileSet*)&player->trayTiles; return (const TrayTileSet*)&player->trayTiles;
} /* model_getPlayerTile */ } /* model_getPlayerTile */
void static void
model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile ) addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile )
{ {
PlayerCtxt* player = &model->players[turn]; PlayerCtxt* player = &model->players[turn];
short i; short i;
TileBit bits = 0;
XP_ASSERT( player->trayTiles.nTiles < MAX_TRAY_TILES ); XP_ASSERT( player->trayTiles.nTiles < MAX_TRAY_TILES );
XP_ASSERT( index >= 0 );
if ( index < 0 ) {
index = player->trayTiles.nTiles;
}
/* move tiles up to make room */ /* move tiles up to make room */
for ( i = player->trayTiles.nTiles; i > index; --i ) { for ( i = player->trayTiles.nTiles; i > index; --i ) {
player->trayTiles.tiles[i] = player->trayTiles.tiles[i-1]; player->trayTiles.tiles[i] = player->trayTiles.tiles[i-1];
bits |= (3 << (i-2));
} }
++player->trayTiles.nTiles; ++player->trayTiles.nTiles;
player->trayTiles.tiles[index] = tile; player->trayTiles.tiles[index] = tile;
} /* addPlayerTile */
bits |= (1 << index); void
notifyTrayListeners( model, turn, bits ); model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile )
{
PlayerCtxt* player = &model->players[turn];
if ( index < 0 ) {
index = player->trayTiles.nTiles;
}
addPlayerTile( model, turn, index, tile );
notifyTrayListeners( model, turn, index, player->trayTiles.nTiles );
} /* model_addPlayerTile */ } /* model_addPlayerTile */
void
model_moveTileOnTray( ModelCtxt* model, XP_S16 turn, XP_S16 indexCur,
XP_S16 indexNew )
{
Tile tile = removePlayerTile( model, turn, indexCur );
addPlayerTile( model, turn, indexNew, tile );
notifyTrayListeners( model, turn, indexCur, indexNew );
} /* model_moveTileOnTray */
static void static void
assignPlayerTiles( ModelCtxt* model, XP_S16 turn, TrayTileSet* tiles ) assignPlayerTiles( ModelCtxt* model, XP_S16 turn, TrayTileSet* tiles )
{ {
@ -1367,11 +1413,12 @@ notifyBoardListeners( ModelCtxt* model, XP_U16 turn, XP_U16 col, XP_U16 row,
} /* notifyBoardListeners */ } /* notifyBoardListeners */
static void static void
notifyTrayListeners( ModelCtxt* model, XP_U16 turn, TileBit bits ) notifyTrayListeners( ModelCtxt* model, XP_U16 turn, XP_S16 index1,
XP_S16 index2 )
{ {
if ( model->vol.trayListenerFunc != NULL ) { if ( model->vol.trayListenerFunc != NULL ) {
(*model->vol.trayListenerFunc)( model->vol.trayListenerData, turn, (*model->vol.trayListenerFunc)( model->vol.trayListenerData, turn,
bits ); index1, index2 );
} }
} /* notifyTrayListeners */ } /* notifyTrayListeners */

View file

@ -127,6 +127,8 @@ Tile model_getPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index );
Tile model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index ); Tile model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index );
void model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, void model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index,
Tile tile ); Tile tile );
void model_moveTileOnTray( ModelCtxt* model, XP_S16 turn, XP_S16 indexCur,
XP_S16 indexNew );
/* As an optimization, return a pointer to the model's array of tiles for a /* As an optimization, return a pointer to the model's array of tiles for a
player. Don't even think about modifying the array!!!! */ player. Don't even think about modifying the array!!!! */
@ -134,9 +136,13 @@ const TrayTileSet* model_getPlayerTiles( ModelCtxt* model, XP_S16 turn );
XP_U16 model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn ); XP_U16 model_getNumTilesInTray( ModelCtxt* model, XP_S16 turn );
XP_U16 model_getNumTilesTotal( ModelCtxt* model, XP_S16 turn ); XP_U16 model_getNumTilesTotal( ModelCtxt* model, XP_S16 turn );
void model_moveBoardToTray( ModelCtxt* model, XP_S16 turn, XP_S16 index ); void model_moveBoardToTray( ModelCtxt* model, XP_S16 turn,
XP_U16 col, XP_U16 row, XP_U16 trayOffset );
void model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, void model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col,
XP_U16 row, XP_S16 tileIndex, Tile blankFace ); XP_U16 row, XP_S16 tileIndex, Tile blankFace );
void model_moveTileOnBoard( ModelCtxt* model, XP_S16 turn, XP_U16 colCur,
XP_U16 rowCur, XP_U16 colNew, XP_U16 rowNew );
XP_S16 model_trayContains( ModelCtxt* model, XP_S16 turn, Tile tile ); XP_S16 model_trayContains( ModelCtxt* model, XP_S16 turn, Tile tile );
@ -184,7 +190,8 @@ typedef void (*BoardListener)(void* data, XP_U16 turn, XP_U16 col,
XP_U16 row, XP_Bool added ); XP_U16 row, XP_Bool added );
void model_setBoardListener( ModelCtxt* model, BoardListener bl, void model_setBoardListener( ModelCtxt* model, BoardListener bl,
void* data ); void* data );
typedef void (*TrayListener)(void* data, XP_U16 turn, TileBit bits ); typedef void (*TrayListener)( void* data, XP_U16 turn,
XP_S16 index1, XP_S16 index2 );
void model_setTrayListener( ModelCtxt* model, TrayListener bl, void model_setTrayListener( ModelCtxt* model, TrayListener bl,
void* data ); void* data );
void model_foreachPendingCell( ModelCtxt* model, XP_S16 turn, void model_foreachPendingCell( ModelCtxt* model, XP_S16 turn,

View file

@ -1,6 +1,6 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ /* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* /*
* Copyright 1997 - 2007 by Eric House (xwords@eehouse.org). All rights reserved. * Copyright 1997 - 2008 by Eric House (xwords@eehouse.org). All rights reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -18,6 +18,7 @@
*/ */
#include "boardp.h" #include "boardp.h"
#include "dragdrpp.h"
#include "engine.h" #include "engine.h"
#include "draw.h" #include "draw.h"
#include "strutils.h" #include "strutils.h"
@ -27,13 +28,9 @@ extern "C" {
#endif #endif
/****************************** prototypes ******************************/ /****************************** prototypes ******************************/
static XP_Bool startDividerDrag( BoardCtxt* board );
static XP_Bool startTileDrag( BoardCtxt* board, XP_U8 startIndex );
static void figureDividerRect( BoardCtxt* board, XP_Rect* rect ); static void figureDividerRect( BoardCtxt* board, XP_Rect* rect );
static void drawPendingScore( BoardCtxt* board, XP_Bool hasCursor ); static void drawPendingScore( BoardCtxt* board, XP_Bool hasCursor );
static void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1, static XP_U16 countTilesToShow( BoardCtxt* board );
XP_U16 tileIndex2 );
static XP_Bool endTileDragIndex( BoardCtxt* board, TileBit last );
static XP_S16 static XP_S16
trayLocToIndex( BoardCtxt* board, XP_U16 loc ) trayLocToIndex( BoardCtxt* board, XP_U16 loc )
@ -48,7 +45,7 @@ trayLocToIndex( BoardCtxt* board, XP_U16 loc )
return loc; return loc;
} /* trayLocToIndex */ } /* trayLocToIndex */
static XP_S16 XP_S16
pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* onDividerP ) pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* onDividerP )
{ {
XP_S16 result = -1; /* not on a tile */ XP_S16 result = -1; /* not on a tile */
@ -99,11 +96,32 @@ figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect )
} }
} /* figureTileRect */ } /* figureTileRect */
/* When drawing tray mid-drag:
*
* Rule is not to touch the model.
*
* Cases: Tile's been dragged into tray (but not yet dropped.); tile's been
* dragged out of tray (but not yet dropped); and tile's been dragged within
* tray. More's the point, there's an added tile and a removed one. We draw
* the added tile extra, and skip the removed one.
*
* We're walking two arrays at once, backwards. The first is the tile rects
* themselves. If the dirty bit is set, something must get drawn. The second
* is the model's view of tiles augmented by drag-and-drop. D-n-d may have
* removed a tile from the tray (for drawing purposes only), have added one,
* or both (drag-within-tray case). Since a drag lasts only until pen-up,
* there's never more than one tile involved. Adjustment is never by more
* than one.
*
* So while one counter (i) walks the array of rects, we can't use it
* unmodified to fetch from the model. Instead we increment or decrement it
* based on the drag state.
*/
void void
drawTray( BoardCtxt* board ) drawTray( BoardCtxt* board )
{ {
XP_Rect tileRect; XP_Rect tileRect;
short i;
if ( (board->trayInvalBits != 0) || board->dividerInvalid ) { if ( (board->trayInvalBits != 0) || board->dividerInvalid ) {
XP_S16 turn = board->selPlayer; XP_S16 turn = board->selPlayer;
@ -122,23 +140,23 @@ drawTray( BoardCtxt* board )
} }
#endif #endif
/* if ( board->eraseTray ) { */
/* draw_clearRect( board->draw, &board->trayBounds ); */
/* board->eraseTray = XP_FALSE; */
/* } */
if ( (board->trayVisState != TRAY_HIDDEN) && dictionary != NULL ) { if ( (board->trayVisState != TRAY_HIDDEN) && dictionary != NULL ) {
XP_Bool showFaces = board->trayVisState == TRAY_REVEALED; XP_Bool showFaces = board->trayVisState == TRAY_REVEALED;
Tile blank = dict_getBlankTile( dictionary ); Tile blank = dict_getBlankTile( dictionary );
if ( turn >= 0 ) { if ( turn >= 0 ) {
XP_U16 numInTray = showFaces? XP_S16 i; /* which tile slot are we drawing in */
model_getNumTilesInTray( board->model, turn ): XP_U16 ddAddedIndx, ddRmvdIndx;
model_getNumTilesTotal( board->model, turn ); XP_U16 numInTray = countTilesToShow( board );
XP_Bool isBlank;
XP_Bool isADrag = dragDropInProgress( board );
dragDropGetTrayChanges( board, &ddRmvdIndx, &ddAddedIndx );
/* draw in reverse order so drawing happens after /* draw in reverse order so drawing happens after
erasing */ erasing */
for ( i = MAX_TRAY_TILES - 1; i >= 0; --i ) { for ( i = MAX_TRAY_TILES - 1;
i >= 0; --i ) {
CellFlags flags = CELL_NONE; CellFlags flags = CELL_NONE;
XP_U16 mask = 1 << i; XP_U16 mask = 1 << i;
@ -161,28 +179,41 @@ drawTray( BoardCtxt* board )
XP_UCHAR* textP = (XP_UCHAR*)NULL; XP_UCHAR* textP = (XP_UCHAR*)NULL;
XP_U8 traySelBits = board->traySelBits[turn]; XP_U8 traySelBits = board->traySelBits[turn];
XP_S16 value; XP_S16 value;
Tile tile = model_getPlayerTile( board->model, Tile tile;
turn, i );
if ( dict_faceIsBitmap( dictionary, tile ) ) { if ( ddAddedIndx == i ) {
bitmap = dict_getFaceBitmap( dictionary, tile, dragDropTileInfo( board, &tile, &isBlank );
XP_TRUE );
} else { } else {
textP = buf; XP_U16 modIndex = i;
dict_tilesToString( dictionary, &tile, 1, if ( ddAddedIndx < i ) {
textP, sizeof(buf) ); --modIndex;
}
/* while we're right of the removal area,
draw the one from the right to cover. */
if ( ddRmvdIndx <= modIndex /*slotIndx*/ ) {
++modIndex;
}
tile = model_getPlayerTile( board->model,
turn, modIndex );
isBlank = tile == blank;
} }
textP = getTileDrawInfo( board, tile, isBlank,
&bitmap, &value,
buf, sizeof(buf) );
if ( board->hideValsInTray if ( board->hideValsInTray
&& !board->showCellValues ) { && !board->showCellValues ) {
value = -1; value = -1;
} else {
value = dict_getTileValue( dictionary, tile );
} }
if ( (traySelBits & (1<<i)) != 0 ) { if ( isADrag ) {
if ( ddAddedIndx == i ) {
flags |= CELL_HIGHLIGHT;
}
} else if ( (traySelBits & (1<<i)) != 0 ) {
flags |= CELL_HIGHLIGHT; flags |= CELL_HIGHLIGHT;
} }
if ( tile == blank ) { if ( isBlank ) {
flags |= CELL_ISBLANK; flags |= CELL_ISBLANK;
} }
@ -199,7 +230,7 @@ drawTray( BoardCtxt* board )
XP_Rect divider; XP_Rect divider;
figureDividerRect( board, &divider ); figureDividerRect( board, &divider );
draw_drawTrayDivider( board->draw, &divider, draw_drawTrayDivider( board->draw, &divider,
board->divDragState.dragInProgress ); dragDropIsDividerDrag(board) );
board->dividerInvalid = XP_FALSE; board->dividerInvalid = XP_FALSE;
} }
@ -216,42 +247,69 @@ drawTray( BoardCtxt* board )
} /* drawTray */ } /* drawTray */
XP_UCHAR*
getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
XP_Bitmap* bitmap, XP_S16* value, XP_UCHAR* buf, XP_U16 len )
{
XP_UCHAR* face = NULL;
DictionaryCtxt* dict = model_getDictionary( board->model );
if ( isBlank ) {
tile = dict_getBlankTile( dict );
}
*value = dict_getTileValue( dict, tile );
if ( dict_faceIsBitmap( dict, tile ) ) {
*bitmap = dict_getFaceBitmap( dict, tile, XP_TRUE );
} else {
dict_tilesToString( dict, &tile, 1, buf, len );
face = buf;
}
return face;
}
static XP_U16
countTilesToShow( BoardCtxt* board )
{
XP_U16 numToShow;
XP_S16 selPlayer = board->selPlayer;
XP_U16 ddAddedIndx, ddRemovedIndx;
XP_ASSERT( selPlayer >= 0 );
if ( board->trayVisState == TRAY_REVEALED ) {
numToShow = model_getNumTilesInTray( board->model, selPlayer );
} else {
numToShow = model_getNumTilesTotal( board->model, selPlayer );
}
dragDropGetTrayChanges( board, &ddRemovedIndx, &ddAddedIndx );
if ( ddAddedIndx < MAX_TRAY_TILES ) {
++numToShow;
}
if ( ddRemovedIndx < MAX_TRAY_TILES ) {
--numToShow;
}
XP_ASSERT( numToShow <= MAX_TRAY_TILES );
return numToShow;
} /* countTilesToShow */
static void static void
drawPendingScore( BoardCtxt* board, XP_Bool hasCursor ) drawPendingScore( BoardCtxt* board, XP_Bool hasCursor )
{ {
/* Draw the pending score down in the last tray's rect */ /* Draw the pending score down in the last tray's rect */
if ( board->trayVisState == TRAY_REVEALED ) { if ( countTilesToShow( board ) < MAX_TRAY_TILES ) {
XP_U16 selPlayer = board->selPlayer; XP_U16 selPlayer = board->selPlayer;
XP_U16 tilesInTray = model_getNumTilesInTray( board->model, selPlayer); XP_S16 turnScore = 0;
if ( tilesInTray < MAX_TRAY_TILES ) { XP_Rect lastTileR;
XP_S16 turnScore = 0; (void)getCurrentMoveScoreIfLegal( board->model, selPlayer,
XP_Rect lastTileR; (XWStreamCtxt*)NULL, &turnScore );
figureTrayTileRect( board, MAX_TRAY_TILES-1, &lastTileR );
(void)getCurrentMoveScoreIfLegal( board->model, selPlayer, draw_score_pendingScore( board->draw, &lastTileR, turnScore,
(XWStreamCtxt*)NULL, &turnScore ); selPlayer,
figureTrayTileRect( board, MAX_TRAY_TILES-1, &lastTileR ); hasCursor?CELL_ISCURSOR:CELL_NONE );
draw_score_pendingScore( board->draw, &lastTileR, turnScore,
selPlayer,
hasCursor?CELL_ISCURSOR:CELL_NONE );
}
} }
} /* drawPendingScore */ } /* drawPendingScore */
#ifdef DEBUG
static XP_U16
countSelectedTiles( XP_U8 ti )
{
XP_U16 result = 0;
while ( ti != 0 ) {
++result;
ti &= ti-1;
}
return result;
} /* countSelectedTiles */
#endif
static void static void
figureDividerRect( BoardCtxt* board, XP_Rect* rect ) figureDividerRect( BoardCtxt* board, XP_Rect* rect )
{ {
@ -293,66 +351,38 @@ handleTrayDuringTrade( BoardCtxt* board, XP_S16 index )
} /* handleTrayDuringTrade */ } /* handleTrayDuringTrade */
static XP_Bool static XP_Bool
handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider, handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider )
XP_Bool waitPenUp )
{ {
XP_Bool result = XP_FALSE; XP_Bool result = XP_FALSE;
XP_U16 selPlayer = board->selPlayer; XP_U16 selPlayer = board->selPlayer;
if ( onDivider ) { if ( onDivider ) {
result = startDividerDrag( board ); /* do nothing */
} else if ( board->tradeInProgress[selPlayer] } else if ( board->tradeInProgress[selPlayer] ) {
/* && MY_TURN(board) */ ) {
if ( index >= 0 ) { if ( index >= 0 ) {
result = handleTrayDuringTrade( board, index ); result = handleTrayDuringTrade( board, index );
} }
} else if ( index >= 0 ) { } else if ( index >= 0 ) {
TileBit newIndex = 1 << index; result = moveTileToArrowLoc( board, (XP_U8)index );
BoardArrow* arrow = &board->boardArrow[selPlayer]; if ( !result ) {
TileBit newBits = 1 << index;
if ( !arrow->visible ) { XP_U8 selBits = board->traySelBits[selPlayer];
XP_U8 selFlags = board->traySelBits[selPlayer];
/* Tap on selected tile unselects. If we don't do this, /* Tap on selected tile unselects. If we don't do this,
then there's no way to unselect and so no way to turn then there's no way to unselect and so no way to turn
off the placement arrow */ off the placement arrow */
if ( !waitPenUp && newIndex == selFlags ) { if ( newBits == selBits ) {
board_invalTrayTiles( board, selFlags ); board_invalTrayTiles( board, selBits );
selFlags = NO_TILES; board->traySelBits[selPlayer] = NO_TILES;
board->traySelBits[selPlayer] = selFlags; } else if ( selBits != 0 ) {
result = XP_TRUE; XP_U16 selIndex = indexForBits( selBits );
model_moveTileOnTray( board->model, board->selPlayer,
selIndex, index );
board->traySelBits[selPlayer] = NO_TILES;
} else { } else {
result = startTileDrag( board, newIndex ); board_invalTrayTiles( board, newBits );
if ( !waitPenUp ) { board->traySelBits[selPlayer] = newBits;
/* key interface means pen up and down happen in the same
event. No dragging. */
result = endTileDragIndex( board, newIndex ) || result;
}
} }
} result = XP_TRUE;
}
return result;
} /* handleActionInTray */
XP_Bool
handlePenDownInTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_Bool onDivider = XP_FALSE;
XP_S16 index = pointToTileIndex( board, x, y, &onDivider );
return handleActionInTray( board, index, onDivider, XP_TRUE );
} /* handlePenDownInTray */
static XP_Bool
handlePenUpTrayInt( BoardCtxt* board, XP_S16 index )
{
XP_Bool result = XP_FALSE;
if ( index >= 0 ) {
XP_U16 selPlayer = board->selPlayer;
BoardArrow* arrow = &board->boardArrow[selPlayer];
if ( arrow->visible ) {
result = moveTileToArrowLoc( board, (XP_U8)index );
} }
} else if ( index == -(MAX_TRAY_TILES) ) { /* pending score tile */ } else if ( index == -(MAX_TRAY_TILES) ) { /* pending score tile */
result = board_commitTurn( board ); result = board_commitTurn( board );
@ -361,85 +391,17 @@ handlePenUpTrayInt( BoardCtxt* board, XP_S16 index )
(void)board_replaceTiles( board ); (void)board_replaceTiles( board );
result = XP_TRUE; result = XP_TRUE;
} }
return result; return result;
} /* handlePenUpTray */ } /* handleActionInTray */
XP_Bool XP_Bool
handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y ) handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
{ {
XP_Bool ignore; XP_Bool onDivider;
XP_S16 index = pointToTileIndex( board, x, y, &ignore ); XP_S16 index = pointToTileIndex( board, x, y, &onDivider );
return handlePenUpTrayInt( board, index ); return handleActionInTray( board, index, onDivider );
} /* handlePenUpTray */ } /* handlePenUpTray */
static XP_Bool
startTileDrag( BoardCtxt* board, TileBit startBit/* , XP_U16 x, XP_U16 y */ )
{
XP_Bool result = XP_FALSE;
XP_U16 turn = board->selPlayer;
XP_U8 startSel = board->traySelBits[turn];
TileDragState* state = &board->tileDragState;
XP_ASSERT( countSelectedTiles( startBit ) == 1 );
XP_ASSERT( !state->dragInProgress );
state->wasHilited = startSel == startBit;
state->selectionAtStart = startSel;
state->movePending = XP_TRUE;
state->dragInProgress = XP_TRUE;
state->prevIndex = board->traySelBits[turn] = startBit;
if ( !state->wasHilited ) {
board_invalTrayTiles( board, (TileBit)(startBit | startSel) );
result = XP_TRUE;
}
return result;
} /* startTileDrag */
static void
moveTileInTray( BoardCtxt* board, TileBit prevTile, TileBit newTile )
{
XP_S16 selPlayer = board->selPlayer;
ModelCtxt* model = board->model;
XP_U16 moveTo = indexForBits( prevTile );
XP_U16 moveFrom = indexForBits( newTile );
Tile tile;
XP_U16 dividerLoc;
tile = model_removePlayerTile( model, selPlayer, moveFrom );
model_addPlayerTile( model, selPlayer, moveTo, tile );
dividerLoc = board->dividerLoc[selPlayer];
if ( moveTo < dividerLoc || moveFrom < dividerLoc ) {
server_resetEngine( board->server, selPlayer );
}
} /* moveTileInTray */
TileBit
continueTileDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
TileDragState* state = &board->tileDragState;
TileBit overTile = 0;
XP_S16 index = pointToTileIndex( board, x, y, (XP_Bool*)NULL );
if ( index >= 0 ) {
overTile = 1 << index;
if ( overTile != state->prevIndex ) {
moveTileInTray( board, overTile, state->prevIndex );
state->movePending = XP_FALSE;
state->wasHilited = XP_FALSE; // so we won't deselect
state->prevIndex = board->traySelBits[board->selPlayer] = overTile;
}
}
return overTile;
} /* continueTileDrag */
XP_U16 XP_U16
indexForBits( XP_U8 bits ) indexForBits( XP_U8 bits )
{ {
@ -455,123 +417,48 @@ indexForBits( XP_U8 bits )
return result; return result;
} /* indexForBits */ } /* indexForBits */
static XP_Bool
endTileDragIndex( BoardCtxt* board, TileBit last )
{
XP_Bool result = XP_FALSE;
XP_U16 selPlayer = board->selPlayer;
TileDragState* state = &board->tileDragState;
if ( state->movePending ) { /* no drag took place */
if ( state->wasHilited ) { /* if the user just clicked; deselect */
board_invalTrayTiles( board, state->selectionAtStart );
board->traySelBits[selPlayer] = NO_TILES;
result = XP_TRUE;
} else if ( (last > 0)
&& !board->boardArrow[selPlayer].visible
&& (state->selectionAtStart != NO_TILES ) ) {
if ( model_getCurrentMoveCount( board->model, selPlayer) == 0 ) {
moveTileInTray( board, last, state->selectionAtStart );
board->traySelBits[selPlayer] = NO_TILES;
} else {
board_invalTrayTiles(
board,
(TileBit)(state->selectionAtStart|last) );
board->traySelBits[selPlayer] = last;
}
result = XP_TRUE;
}
} else {
board_invalTrayTiles( board, state->prevIndex );
board->traySelBits[selPlayer] = NO_TILES;
result = XP_TRUE;
}
state->dragInProgress = XP_FALSE;
return result;
} /* endTileDragIndex */
XP_Bool XP_Bool
endTileDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
TileBit newTile = continueTileDrag( board, x, y );
return endTileDragIndex( board, newTile );
} /* endTileDrag */
static XP_Bool
startDividerDrag( BoardCtxt* board )
{
board->divDragState.dragInProgress = XP_TRUE;
board->dividerInvalid = XP_TRUE;
return XP_TRUE;
} /* startDividerDrag */
static void
dividerMoved( BoardCtxt* board, XP_U8 newLoc ) dividerMoved( BoardCtxt* board, XP_U8 newLoc )
{ {
XP_U8 oldLoc = board->dividerLoc[board->selPlayer]; XP_U8 oldLoc = board->dividerLoc[board->selPlayer];
board->dividerLoc[board->selPlayer] = newLoc; XP_Bool moved = oldLoc != newLoc;
if ( moved ) {
board->dividerLoc[board->selPlayer] = newLoc;
/* This divider's index corresponds to the tile it's to the left of, and /* This divider's index corresponds to the tile it's to the left of, and
there's no need to invalidate any tiles to the left of the uppermore there's no need to invalidate any tiles to the left of the uppermore
divider position. */ divider position. */
if ( oldLoc > newLoc ) { if ( oldLoc > newLoc ) {
--oldLoc; --oldLoc;
} else { } else {
--newLoc; --newLoc;
}
invalTrayTilesBetween( board, newLoc, oldLoc );
board->dividerInvalid = XP_TRUE;
/* changed number of available tiles */
board_resetEngine( board );
} }
invalTrayTilesBetween( board, newLoc, oldLoc ); return moved;
board->dividerInvalid = XP_TRUE;
/* changed number of available tiles */
board_resetEngine( board );
} /* dividerMoved */ } /* dividerMoved */
XP_Bool
continueDividerDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_U8 newOffset;
XP_U16 trayScale = board->trayScaleH;
XP_Bool result = XP_FALSE;
XP_ASSERT( board->divDragState.dragInProgress );
/* Pen might have been dragged out of the tray */
if ( rectContainsPt( &board->trayBounds, x, y ) ) {
x -= board->trayBounds.left;
newOffset = x / trayScale;
if ( (x % trayScale) > (trayScale/2) ) {
++newOffset;
}
result = newOffset != board->dividerLoc[board->selPlayer];
if ( result ) {
dividerMoved( board, newOffset );
}
}
return result;
} /* continueDividerDrag */
XP_Bool
endDividerDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_Bool result = XP_TRUE; /* b/c hilited state looks different */
(void)continueDividerDrag( board, x, y );
board->dividerInvalid = XP_TRUE;
board->divDragState.dragInProgress = XP_FALSE;
return result;
} /* endDividerDrag */
void void
board_invalTrayTiles( BoardCtxt* board, TileBit what ) board_invalTrayTiles( BoardCtxt* board, TileBit what )
{ {
board->trayInvalBits |= what; board->trayInvalBits |= what;
} /* invalTrayTiles */ } /* invalTrayTiles */
static void void
invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex )
{
TileBit bits = 0;
while ( tileIndex < MAX_TRAY_TILES ) {
bits |= 1 << tileIndex++;
}
board_invalTrayTiles( board, bits );
}
void
invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1, invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
XP_U16 tileIndex2 ) XP_U16 tileIndex2 )
{ {
@ -710,7 +597,7 @@ board_moveDivider( BoardCtxt* board, XP_Bool right )
loc += right? 1:-1; loc += right? 1:-1;
loc %= MAX_TRAY_TILES + 1; loc %= MAX_TRAY_TILES + 1;
dividerMoved( board, loc ); (void)dividerMoved( board, loc );
} }
return result; return result;
} /* board_moveDivider */ } /* board_moveDivider */

View file

@ -1,6 +1,7 @@
/* -*- mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */ /* -*- mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/* /*
* Copyright 1997-2007 by Eric House (xwords@eehouse.org). All rights reserved. * Copyright 1997-2008 by Eric House (xwords@eehouse.org). All rights
* reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -71,7 +72,7 @@ eraseRect( GtkDrawCtx* dctx, const XP_Rect* rect )
} /* eraseRect */ } /* eraseRect */
static void static void
frameRect( GtkDrawCtx* dctx, XP_Rect* rect ) frameRect( GtkDrawCtx* dctx, const XP_Rect* rect )
{ {
gdk_draw_rectangle( DRAW_WHAT(dctx), gdk_draw_rectangle( DRAW_WHAT(dctx),
dctx->drawGC, FALSE, rect->left, rect->top, dctx->drawGC, FALSE, rect->left, rect->top,
@ -431,55 +432,46 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
rect->height ); rect->height );
} }
/* draw the bonus colors only if we're not putting a "tile" there */ /* We draw just an empty, potentially colored, square IFF there's nothing
if ( !!letter ) { in the cell or if CELL_DRAGSRC is set */
if ( *letter == LETTER_NONE && bonus != BONUS_NONE ) { if ( (flags & CELL_DRAGSRC) != 0 || ( !!letter && *letter == LETTER_NONE ) ) {
XP_ASSERT( bonus <= 4 ); if ( bonus != BONUS_NONE ) {
gdk_gc_set_foreground( dctx->drawGC, &dctx->bonusColors[bonus-1] ); gdk_gc_set_foreground( dctx->drawGC, &dctx->bonusColors[bonus-1] );
gdk_draw_rectangle( DRAW_WHAT(dctx), gdk_draw_rectangle( DRAW_WHAT(dctx), dctx->drawGC, TRUE,
dctx->drawGC,
TRUE,
rectInset.left, rectInset.top, rectInset.left, rectInset.top,
rectInset.width+1, rectInset.height+1 ); rectInset.width+1, rectInset.height+1 );
}
if ( (flags & CELL_ISSTAR) != 0 ) {
draw_string_at( dctx, "*", rect->height, rect, XP_GTK_JUST_CENTER,
&dctx->black, NULL );
}
} else if ( !!letter ) {
GdkColor* foreground;
} else if ( *letter != LETTER_NONE ) { if ( !highlight ) {
GdkColor* foreground; gdk_gc_set_foreground( dctx->drawGC, &dctx->tileBack );
}
gdk_draw_rectangle( DRAW_WHAT(dctx), dctx->drawGC, TRUE,
rectInset.left, rectInset.top,
rectInset.width+1, rectInset.height+1 );
if ( !highlight ) { foreground = highlight? &dctx->white : &dctx->playerColors[owner];
gdk_gc_set_foreground( dctx->drawGC, &dctx->tileBack ); draw_string_at( dctx, letter, rectInset.height-2, &rectInset,
} XP_GTK_JUST_CENTER, foreground, NULL );
gdk_draw_rectangle( DRAW_WHAT(dctx),
dctx->drawGC,
TRUE,
rectInset.left, rectInset.top,
rectInset.width+1, rectInset.height+1 );
foreground = highlight? &dctx->white : &dctx->playerColors[owner]; if ( (flags & CELL_ISBLANK) != 0 ) {
draw_string_at( dctx, letter, rectInset.height-2, gdk_draw_arc( DRAW_WHAT(dctx), dctx->drawGC,
&rectInset, XP_GTK_JUST_CENTER, 0, /* filled */
foreground, NULL ); rect->left, /* x */
rect->top, /* y */
if ( (flags & CELL_ISBLANK) != 0 ) { rect->width,/*width, */
gdk_draw_arc( DRAW_WHAT(dctx), dctx->drawGC, rect->height,/*width, */
0, /* filled */ 0, 360*64 );
rect->left, /* x */
rect->top, /* y */
rect->width,/*width, */
rect->height,/*width, */
0, 360*64 );
}
} }
} else if ( !!bitmap ) { } else if ( !!bitmap ) {
drawBitmapFromLBS( dctx, bitmap, rect ); drawBitmapFromLBS( dctx, bitmap, rect );
} }
if ( (flags & CELL_ISSTAR) != 0 ) {
draw_string_at( dctx, "*", rect->height,
rect, XP_GTK_JUST_CENTER,
&dctx->black, NULL );
}
drawHintBorders( dctx, rect, hintAtts ); drawHintBorders( dctx, rect, hintAtts );
if ( (flags & CELL_ISCURSOR) != 0 ) { if ( (flags & CELL_ISCURSOR) != 0 ) {
@ -525,15 +517,18 @@ gtk_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 owner,
} /* gtk_draw_trayBegin */ } /* gtk_draw_trayBegin */
static void static void
gtk_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP, gtkDrawTileImpl( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
XP_Bitmap bitmap, XP_S16 val, CellFlags flags ) XP_Bitmap bitmap, XP_S16 val, CellFlags flags,
XP_Bool clearBack )
{ {
XP_UCHAR numbuf[3]; XP_UCHAR numbuf[3];
gint len; gint len;
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect insetR = *rect; XP_Rect insetR = *rect;
eraseRect( dctx, &insetR ); if ( clearBack ) {
eraseRect( dctx, &insetR );
}
if ( val >= 0 ) { if ( val >= 0 ) {
GdkColor* foreground = &dctx->playerColors[dctx->trayOwner]; GdkColor* foreground = &dctx->playerColors[dctx->trayOwner];
@ -541,17 +536,18 @@ gtk_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
insetRect( &insetR, 1 ); insetRect( &insetR, 1 );
if ( clearBack ) {
gdk_gc_set_foreground( dctx->drawGC, &dctx->tileBack );
gdk_draw_rectangle( DRAW_WHAT(dctx),
dctx->drawGC,
XP_TRUE,
insetR.left, insetR.top, insetR.width,
insetR.height );
}
formatRect.left += 3; formatRect.left += 3;
formatRect.width -= 6; formatRect.width -= 6;
gdk_gc_set_foreground( dctx->drawGC, &dctx->tileBack );
gdk_draw_rectangle( DRAW_WHAT(dctx),
dctx->drawGC,
TRUE,
insetR.left, insetR.top, insetR.width,
insetR.height );
if ( !!textP ) { if ( !!textP ) {
if ( *textP != LETTER_NONE ) { /* blank */ if ( *textP != LETTER_NONE ) { /* blank */
draw_string_at( dctx, textP, formatRect.height>>1, draw_string_at( dctx, textP, formatRect.height>>1,
@ -593,6 +589,25 @@ gtk_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
} /* gtk_draw_drawTile */ } /* gtk_draw_drawTile */
static void
gtk_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
XP_Bitmap bitmap, XP_S16 val, CellFlags flags )
{
gtkDrawTileImpl( p_dctx, rect, textP, bitmap, val, flags, XP_TRUE );
}
#ifdef POINTER_SUPPORT
static void
gtk_draw_drawTileMidDrag( DrawCtx* p_dctx, const XP_Rect* rect,
const XP_UCHAR* textP, XP_Bitmap bitmap,
XP_S16 val, CellFlags flags )
{
gtkDrawTileImpl( p_dctx, rect, textP, bitmap, val,
flags | CELL_HIGHLIGHT,
XP_FALSE );
}
#endif
static void static void
gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect, gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect,
CellFlags flags ) CellFlags flags )
@ -635,7 +650,7 @@ gtk_draw_drawTrayDivider( DrawCtx* p_dctx, const XP_Rect* rect,
++r.left; ++r.left;
r.width -= selected? 2:1; r.width -= selected? 2:1;
if ( selected ) { if ( selected ) {
--r.height; --r.height;
} }
gdk_gc_set_foreground( dctx->drawGC, &dctx->black ); gdk_gc_set_foreground( dctx->drawGC, &dctx->black );
@ -1030,6 +1045,9 @@ gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
SET_VTABLE_ENTRY( dctx->vtable, draw_trayBegin, gtk ); SET_VTABLE_ENTRY( dctx->vtable, draw_trayBegin, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawTile, gtk ); SET_VTABLE_ENTRY( dctx->vtable, draw_drawTile, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawTileBack, gtk ); SET_VTABLE_ENTRY( dctx->vtable, draw_drawTileBack, gtk );
#ifdef POINTER_SUPPORT
SET_VTABLE_ENTRY( dctx->vtable, draw_drawTileMidDrag, gtk );
#endif
SET_VTABLE_ENTRY( dctx->vtable, draw_drawTrayDivider, gtk ); SET_VTABLE_ENTRY( dctx->vtable, draw_drawTrayDivider, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawBoardArrow, gtk ); SET_VTABLE_ENTRY( dctx->vtable, draw_drawBoardArrow, gtk );

View file

@ -108,12 +108,13 @@ button_press_event( GtkWidget* XP_UNUSED(widget), GdkEventButton *event,
{ {
XP_Bool redraw, handled; XP_Bool redraw, handled;
globals->mouseDown = XP_TRUE; if ( !globals->mouseDown ) {
globals->mouseDown = XP_TRUE;
redraw = board_handlePenDown( globals->cGlobals.game.board, redraw = board_handlePenDown( globals->cGlobals.game.board,
event->x, event->y, &handled ); event->x, event->y, &handled );
if ( redraw ) { if ( redraw ) {
board_draw( globals->cGlobals.game.board ); board_draw( globals->cGlobals.game.board );
}
} }
return 1; return 1;
} /* button_press_event */ } /* button_press_event */