mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
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:
parent
4c730be669
commit
0b1f4b8f0a
9 changed files with 605 additions and 485 deletions
|
@ -62,6 +62,7 @@
|
|||
#include "LocalizedStrIncludes.h"
|
||||
|
||||
#include "boardp.h"
|
||||
#include "dragdrpp.h"
|
||||
#include "dbgutil.h"
|
||||
|
||||
#define bEND 0x62454e44
|
||||
|
@ -73,8 +74,6 @@ extern "C" {
|
|||
/****************************** prototypes ******************************/
|
||||
static XP_Bool getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
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,
|
||||
XP_Bool skipBlanks );
|
||||
static void figureBoardRect( BoardCtxt* board );
|
||||
|
@ -82,13 +81,11 @@ static void figureBoardRect( BoardCtxt* board );
|
|||
static void drawBoard( BoardCtxt* board );
|
||||
static void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
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 void boardCellChanged( void* board, XP_U16 turn, XP_U16 col,
|
||||
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 boardGameOver( void* board );
|
||||
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 );
|
||||
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 makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
|
||||
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,
|
||||
XP_Bool visible );
|
||||
static XP_Bool board_moveArrow( BoardCtxt* board, XP_Key cursorKey );
|
||||
static void flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
XP_U16* fCol, XP_U16* fRow );
|
||||
#ifdef POINTER_SUPPORT
|
||||
static void drawDragTileIf( BoardCtxt* board );
|
||||
#endif
|
||||
static XP_Bool holdsPendingTile( BoardCtxt* board,
|
||||
XP_U16 pencol, XP_U16 penrow );
|
||||
|
||||
#ifdef KEY_SUPPORT
|
||||
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) */
|
||||
model_setBoardListener( model, boardCellChanged, result );
|
||||
model_setTrayListener( model, boardTileChanged, result );
|
||||
model_setTrayListener( model, boardTilesChanged, result );
|
||||
server_setTurnChangeListener( server, boardTurnChanged, result );
|
||||
server_setGameOverListener( server, boardGameOver, result );
|
||||
|
||||
|
@ -739,7 +737,7 @@ timerFiredForPen( BoardCtxt* board )
|
|||
const XP_UCHAR* text = (XP_UCHAR*)NULL;
|
||||
XP_UCHAR buf[80];
|
||||
|
||||
if ( board->penDownObject == OBJ_BOARD
|
||||
if ( (board->penDownObject == OBJ_BOARD) && !dragDropInProgress(board)
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
&& !board->hintDragInProgress
|
||||
#endif
|
||||
|
@ -958,7 +956,7 @@ board_invalAll( BoardCtxt* board )
|
|||
board->scoreBoardInvalid = XP_TRUE;
|
||||
} /* board_invalAll */
|
||||
|
||||
static void
|
||||
void
|
||||
flipIf( const BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
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 );
|
||||
|
||||
#ifdef POINTER_SUPPORT
|
||||
drawDragTileIf( board );
|
||||
#endif
|
||||
draw_objFinished( board->draw, OBJ_BOARD, &board->boardBounds,
|
||||
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;
|
||||
HintAtts hintAtts;
|
||||
CellFlags flags = CELL_NONE;
|
||||
XP_Bool isOrigin;
|
||||
|
||||
isEmpty = !model_getTile( model, modelCol, modelRow, showPending,
|
||||
selPlayer, &tile, &isBlank,
|
||||
&pending, &recent );
|
||||
selPlayer, &tile, &isBlank,
|
||||
&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 ) {
|
||||
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 );
|
||||
hintAtts = figureHintAtts( board, col, row );
|
||||
|
||||
if ( isEmpty && (col==board->star_row)
|
||||
&& (row==board->star_row ) ) {
|
||||
if ( (col==board->star_row) && (row==board->star_row) ) {
|
||||
flags |= CELL_ISSTAR;
|
||||
}
|
||||
if ( invert ) {
|
||||
|
@ -1835,7 +1845,7 @@ figureBoardRect( BoardCtxt* board )
|
|||
}
|
||||
} /* figureBoardRect */
|
||||
|
||||
static XP_Bool
|
||||
XP_Bool
|
||||
coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP, XP_U16* rowP )
|
||||
{
|
||||
XP_U16 col, row, max;
|
||||
|
@ -1913,7 +1923,7 @@ invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
|||
} /* invalCell */
|
||||
|
||||
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV
|
||||
static XP_Bool
|
||||
XP_Bool
|
||||
pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y, BoardObjectType* wp )
|
||||
{
|
||||
XP_Bool result = XP_TRUE;
|
||||
|
@ -2231,14 +2241,25 @@ static XP_Bool
|
|||
handlePenDownOnBoard( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
||||
{
|
||||
XP_Bool result = XP_FALSE;
|
||||
XP_U16 col, row;
|
||||
/* Start a timer no matter what. After it fires we'll decide whether it's
|
||||
appropriate to handle it. No. That's too expensive */
|
||||
if ( TRADE_IN_PROGRESS(board) && ptOnTradeWindow( board, x, y ) ) {
|
||||
return XP_FALSE;
|
||||
}
|
||||
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
|
||||
if ( board->gi->allowHintRect && board->trayVisState == TRAY_REVEALED ) {
|
||||
} else if ( board->gi->allowHintRect
|
||||
&& (board->trayVisState == TRAY_REVEALED) ) {
|
||||
result = startHintRegionDrag( board, x, y );
|
||||
}
|
||||
#endif
|
||||
|
@ -2329,8 +2350,9 @@ handleLikeDown( BoardCtxt* board, BoardObjectType onWhich, XP_U16 x, XP_U16 y )
|
|||
case OBJ_TRAY:
|
||||
XP_ASSERT( board->trayVisState != TRAY_HIDDEN );
|
||||
|
||||
if ( board->trayVisState != TRAY_REVERSED ) {
|
||||
result = handlePenDownInTray( board, x, y ) || result;
|
||||
if ( board->trayVisState != TRAY_REVERSED
|
||||
&& !board->tradeInProgress[board->selPlayer] ) {
|
||||
result = dragDropStart( board, OBJ_TRAY, x, y ) || result;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -2385,10 +2407,8 @@ board_handlePenMove( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
|||
{
|
||||
XP_Bool result = XP_FALSE;
|
||||
|
||||
if ( board->tileDragState.dragInProgress ) {
|
||||
result = continueTileDrag( board, x, y ) != 0;
|
||||
} else if ( board->divDragState.dragInProgress ) {
|
||||
result = continueDividerDrag( board, x, y ) != 0;
|
||||
if ( dragDropInProgress(board) ) {
|
||||
result = dragDropContinue( board, x, y ) != 0;
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
} else if ( board->gi->allowHintRect
|
||||
&& board->trayVisState == TRAY_REVEALED ) {
|
||||
|
@ -2434,7 +2454,7 @@ moveSelTileToBoardXY( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
|||
return result;
|
||||
} /* moveSelTileToBoardXY */
|
||||
|
||||
static XP_Bool
|
||||
XP_Bool
|
||||
cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool inclPending )
|
||||
{
|
||||
Tile tile;
|
||||
|
@ -2486,41 +2506,37 @@ tryMoveArrow( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
|||
return result;
|
||||
} /* 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
|
||||
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;
|
||||
XP_Bool ignore, isPending;
|
||||
XP_U16 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,
|
||||
board->selPlayer );
|
||||
while ( count-- ) {
|
||||
index = count;
|
||||
model_getCurrentMoveTile( board->model, board->selPlayer,
|
||||
&index, &tile, &col, &row, &ignore );
|
||||
if ( col == modcol && row == modrow ) {
|
||||
model_moveBoardToTray( board->model, board->selPlayer,
|
||||
index );
|
||||
/* the cursor should show up where the tile used to be so it's
|
||||
easy to replace it. */
|
||||
setArrow( board, pencol, penrow );
|
||||
result = XP_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return model_getTile( board->model, modcol, modrow, XP_TRUE,
|
||||
board->selPlayer, &tile, &ignore, &isPending,
|
||||
(XP_Bool*)NULL )
|
||||
&& isPending;
|
||||
} /* holdsPendingTile */
|
||||
|
||||
/* Did I tap on a tile on the board that I have not yet committed? If so,
|
||||
* return it to the tray.
|
||||
*/
|
||||
XP_Bool
|
||||
tryReplaceTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow )
|
||||
{
|
||||
XP_Bool result = XP_FALSE;
|
||||
|
||||
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;
|
||||
} /* tryReplaceTile */
|
||||
|
@ -2549,7 +2565,8 @@ exitTradeMode( BoardCtxt* board )
|
|||
XP_Bool
|
||||
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;
|
||||
|
||||
/* 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. */
|
||||
board->penDownObject = OBJ_NONE;
|
||||
|
||||
if ( board->tileDragState.dragInProgress ) {
|
||||
result = endTileDrag( board, x, y );
|
||||
} else if ( board->divDragState.dragInProgress ) {
|
||||
result = endDividerDrag( board, x, y );
|
||||
if ( dragDropInProgress(board) ) {
|
||||
draw = dragDropEnd( board, x, y, &dragged );
|
||||
}
|
||||
if ( dragged ) {
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
} else if ( board->hintDragInProgress ) {
|
||||
XP_ASSERT( board->gi->allowHintRect );
|
||||
result = finishHintRegionDrag( board, x, y );
|
||||
draw = finishHintRegionDrag( board, x, y ) || draw;
|
||||
#endif
|
||||
} else if ( board->penTimerFired ) {
|
||||
if ( valHintMiniWindowActive( board ) ) {
|
||||
hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT );
|
||||
result = XP_TRUE;
|
||||
draw = XP_TRUE;
|
||||
}
|
||||
/* Need to clean up if there's been any dragging happening */
|
||||
board->penTimerFired = XP_FALSE;
|
||||
|
@ -2580,7 +2597,7 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
|||
switch( onWhich ) {
|
||||
case OBJ_SCORE:
|
||||
if ( prevObj == OBJ_SCORE ) {
|
||||
result = handlePenUpScore( board, x, y );
|
||||
draw = handlePenUpScore( board, x, y ) || draw;
|
||||
}
|
||||
break;
|
||||
case OBJ_BOARD:
|
||||
|
@ -2589,21 +2606,21 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
|||
|
||||
if ( TRADE_IN_PROGRESS(board) ) {
|
||||
if ( ptOnTradeWindow( board, x, y )) {
|
||||
result = exitTradeMode( board );
|
||||
draw = exitTradeMode( board ) || draw;
|
||||
}
|
||||
} else {
|
||||
XP_U16 col, row;
|
||||
coordToCell( board, board->penDownX, board->penDownY,
|
||||
&col, &row );
|
||||
result = handleActionInCell( board, col, row );
|
||||
draw = handleActionInCell( board, col, row ) || draw;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OBJ_TRAY:
|
||||
if ( board->trayVisState == TRAY_REVERSED ) {
|
||||
result = askRevealTray( board );
|
||||
draw = askRevealTray( board ) || draw;
|
||||
} else {
|
||||
result = handlePenUpTray( board, x, y );
|
||||
draw = handlePenUpTray( board, x, y ) || draw;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -2615,7 +2632,7 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
|||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
board->hintDragInProgress = XP_FALSE;
|
||||
#endif
|
||||
return result;
|
||||
return draw;
|
||||
} /* board_handlePenUp */
|
||||
#endif /* #ifdef POINTER_SUPPORT */
|
||||
|
||||
|
@ -2914,8 +2931,6 @@ board_focusChanged( BoardCtxt* board, BoardObjectType typ, XP_Bool gained )
|
|||
draw = invalFocusOwner( board ) || draw;
|
||||
}
|
||||
board->focussed = typ;
|
||||
XP_LOGF( "%s: set focussed to %s", __func__,
|
||||
BoardObjectType_2str(typ) );
|
||||
board->focusHasDived = XP_FALSE;
|
||||
draw = invalFocusOwner( board ) || draw;
|
||||
} else {
|
||||
|
@ -3148,8 +3163,7 @@ replaceLastTile( BoardCtxt* board )
|
|||
index = -1;
|
||||
model_getCurrentMoveTile( board->model, board->selPlayer, &index,
|
||||
&tile, &col, &row, &isBlank );
|
||||
|
||||
model_moveBoardToTray( board->model, board->selPlayer, index );
|
||||
model_moveBoardToTray( board->model, board->selPlayer, col, row, -1 );
|
||||
|
||||
flipIf( board, col, row, &col, &row );
|
||||
setArrow( board, col, row );
|
||||
|
@ -3160,9 +3174,9 @@ replaceLastTile( BoardCtxt* board )
|
|||
return result;
|
||||
} /* replaceLastTile */
|
||||
|
||||
static XP_Bool
|
||||
XP_Bool
|
||||
moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_U16 tileIndex,
|
||||
Tile blankFace )
|
||||
Tile blankFace )
|
||||
{
|
||||
if ( cellOccupied( board, col, row, XP_TRUE ) ) {
|
||||
return XP_FALSE;
|
||||
|
@ -3340,13 +3354,13 @@ boardCellChanged( void* p_board, XP_U16 turn, XP_U16 modelCol, XP_U16 modelRow,
|
|||
} /* boardCellChanged */
|
||||
|
||||
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;
|
||||
if ( turn == board->selPlayer ) {
|
||||
board_invalTrayTiles( board, bits );
|
||||
invalTrayTilesBetween( board, index1, index2 );
|
||||
}
|
||||
} /* boardTileChanged */
|
||||
} /* boardTilesChanged */
|
||||
|
||||
static void
|
||||
boardTurnChanged( void* p_board )
|
||||
|
@ -3380,6 +3394,109 @@ boardGameOver( void* closure )
|
|||
util_notifyGameOver( board->util );
|
||||
} /* 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
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -30,18 +30,29 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct TileDragState {
|
||||
XP_Bool dragInProgress;
|
||||
typedef struct _DragObjInfo {
|
||||
BoardObjectType obj;
|
||||
union {
|
||||
struct {
|
||||
XP_U16 col;
|
||||
XP_U16 row;
|
||||
} board;
|
||||
struct {
|
||||
XP_U16 index;
|
||||
} tray;
|
||||
} u;
|
||||
} DragObjInfo;
|
||||
|
||||
XP_Bool wasHilited;
|
||||
TileBit selectionAtStart;
|
||||
XP_Bool movePending;
|
||||
TileBit prevIndex;
|
||||
} TileDragState;
|
||||
|
||||
typedef struct DividerDragState {
|
||||
typedef struct DragState {
|
||||
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 */
|
||||
XP_U8 col;
|
||||
|
@ -146,8 +157,7 @@ struct BoardCtxt {
|
|||
XP_Bool dividerInvalid;
|
||||
|
||||
XP_Bool scoreBoardInvalid;
|
||||
TileDragState tileDragState;
|
||||
DividerDragState divDragState;
|
||||
DragState dragState;
|
||||
|
||||
MiniWindowStuff miniWindowStuff[2];
|
||||
XP_Bool tradingMiniWindowInvalid;
|
||||
|
@ -182,22 +192,41 @@ struct BoardCtxt {
|
|||
#define TRADE_IN_PROGRESS(b) ((b)->tradeInProgress[(b)->selPlayer]==XP_TRUE)
|
||||
|
||||
/* 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 );
|
||||
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_U16 indexForBits( XP_U8 bits );
|
||||
XP_Bool rectContainsPt( XP_Rect* rect1, XP_S16 x, XP_S16 y );
|
||||
XP_Bool checkRevealTray( BoardCtxt* board );
|
||||
void invalTilesUnderRect( BoardCtxt* board, 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_S16 pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y,
|
||||
XP_Bool* onDividerP );
|
||||
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
|
||||
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,
|
||||
|
|
|
@ -24,6 +24,7 @@ COMMONOBJDIR = ../common/$(PLATFORM)
|
|||
|
||||
COMMONSRC = \
|
||||
$(COMMONDIR)/board.c \
|
||||
$(COMMONDIR)/dragdrpp.c \
|
||||
$(COMMONDIR)/scorebdp.c \
|
||||
$(COMMONDIR)/tray.c \
|
||||
$(COMMONDIR)/draw.c \
|
||||
|
@ -47,6 +48,7 @@ COMMONSRC = \
|
|||
|
||||
COMMON1 = \
|
||||
$(COMMONOBJDIR)/board.o \
|
||||
$(COMMONOBJDIR)/dragdrpp.o \
|
||||
$(COMMONOBJDIR)/tray.o \
|
||||
$(COMMONOBJDIR)/scorebdp.o \
|
||||
$(COMMONOBJDIR)/draw.o \
|
||||
|
|
|
@ -37,6 +37,8 @@ typedef enum {
|
|||
, CELL_ISSTAR = 0x04
|
||||
, CELL_ISCURSOR = 0x08
|
||||
, CELL_ISEMPTY = 0x10 /* of a tray tile slot */
|
||||
, CELL_DRAGSRC = 0x20 /* where drag originated */
|
||||
, CELL_DRAGCUR = 0x40 /* where drag is now */
|
||||
, CELL_ALL = 0xFF
|
||||
} CellFlags;
|
||||
|
||||
|
@ -166,6 +168,12 @@ typedef struct DrawCtxVTable {
|
|||
/* at least 1 of these two will be null*/
|
||||
const XP_UCHAR* text, const XP_Bitmap bitmap,
|
||||
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,
|
||||
CellFlags flags );
|
||||
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_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 ) \
|
||||
CALL_DRAW_NAME2(drawTileBack, (dc), (rect), (f) )
|
||||
#define draw_drawTrayDivider( dc, rect, s ) \
|
||||
|
|
|
@ -48,7 +48,8 @@ static void decrPendingTileCountAt( ModelCtxt* model, XP_U16 col,
|
|||
XP_U16 row );
|
||||
static void notifyBoardListeners( ModelCtxt* model, XP_U16 turn,
|
||||
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 void setModelTileRaw( ModelCtxt* model, XP_U16 col, XP_U16 row,
|
||||
CellTile tile );
|
||||
|
@ -874,30 +875,35 @@ model_getCurrentMoveTile( ModelCtxt* model, XP_S16 turn, XP_S16* index,
|
|||
*tile = pt->tile & TILE_VALUE_MASK;
|
||||
} /* model_getCurrentMoveTile */
|
||||
|
||||
Tile
|
||||
model_removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index )
|
||||
static Tile
|
||||
removePlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index )
|
||||
{
|
||||
PlayerCtxt* player = &model->players[turn];
|
||||
Tile tile;
|
||||
short i;
|
||||
TileBit bits = 0;
|
||||
|
||||
if ( index < 0 ) {
|
||||
index = player->trayTiles.nTiles - 1;
|
||||
} else {
|
||||
XP_ASSERT( index < player->trayTiles.nTiles );
|
||||
}
|
||||
XP_ASSERT( index < player->trayTiles.nTiles );
|
||||
|
||||
tile = player->trayTiles.tiles[index];
|
||||
bits = 1 << index;
|
||||
|
||||
--player->trayTiles.nTiles;
|
||||
for ( i = index; i < player->trayTiles.nTiles; ++i ) {
|
||||
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;
|
||||
} /* model_removePlayerTile */
|
||||
|
||||
|
@ -1003,28 +1009,36 @@ model_moveTrayToBoard( ModelCtxt* model, XP_S16 turn, XP_U16 col, XP_U16 row,
|
|||
} /* model_moveTrayToBoard */
|
||||
|
||||
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;
|
||||
short i;
|
||||
PendingTile* pt;
|
||||
Tile tile;
|
||||
|
||||
player = &model->players[turn];
|
||||
if ( index < 0 ) {
|
||||
index = player->nPending - 1;
|
||||
}
|
||||
for ( pt = player->pendingTiles, index = 0;
|
||||
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;
|
||||
|
||||
if ( (tile & TILE_BLANK_BIT) != 0 ) {
|
||||
tile = dict_getBlankTile( model->vol.dict );
|
||||
}
|
||||
|
||||
model_addPlayerTile( model, turn, -1, tile );
|
||||
model_addPlayerTile( model, turn, trayOffset, tile );
|
||||
|
||||
--player->nPending;
|
||||
for ( i = index; i < player->nPending; ++i ) {
|
||||
|
@ -1038,6 +1052,36 @@ model_moveBoardToTray( ModelCtxt* model, XP_S16 turn, XP_S16 index )
|
|||
invalidateScore( model, turn );
|
||||
} /* 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
|
||||
model_resetCurrentTurn( ModelCtxt* model, XP_S16 whose )
|
||||
{
|
||||
|
@ -1047,7 +1091,10 @@ model_resetCurrentTurn( ModelCtxt* model, XP_S16 whose )
|
|||
player = &model->players[whose];
|
||||
|
||||
while ( player->nPending > 0 ) {
|
||||
model_moveBoardToTray( model, whose, -1 );
|
||||
model_moveBoardToTray( model, whose,
|
||||
player->pendingTiles[0].col,
|
||||
player->pendingTiles[0].row,
|
||||
-1 );
|
||||
}
|
||||
} /* model_resetCurrentTurn */
|
||||
|
||||
|
@ -1104,27 +1151,13 @@ static void
|
|||
putBackOtherPlayersTiles( ModelCtxt* model, XP_U16 notMyTurn,
|
||||
XP_U16 col, XP_U16 row )
|
||||
{
|
||||
XP_S16 turn, j;
|
||||
XP_S16 turn;
|
||||
|
||||
for ( turn = 0; turn < model->nPlayers; ++turn ) {
|
||||
PlayerCtxt* player;
|
||||
|
||||
if ( turn == notMyTurn ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
}
|
||||
model_moveBoardToTray( model, turn, col, row, -1 );
|
||||
}
|
||||
} /* putBackOtherPlayersTiles */
|
||||
|
||||
|
@ -1271,31 +1304,44 @@ model_getPlayerTiles( ModelCtxt* model, XP_S16 turn )
|
|||
return (const TrayTileSet*)&player->trayTiles;
|
||||
} /* model_getPlayerTile */
|
||||
|
||||
void
|
||||
model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile )
|
||||
static void
|
||||
addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index, Tile tile )
|
||||
{
|
||||
PlayerCtxt* player = &model->players[turn];
|
||||
short i;
|
||||
TileBit bits = 0;
|
||||
|
||||
XP_ASSERT( player->trayTiles.nTiles < MAX_TRAY_TILES );
|
||||
|
||||
if ( index < 0 ) {
|
||||
index = player->trayTiles.nTiles;
|
||||
}
|
||||
XP_ASSERT( index >= 0 );
|
||||
|
||||
/* move tiles up to make room */
|
||||
for ( i = player->trayTiles.nTiles; i > index; --i ) {
|
||||
player->trayTiles.tiles[i] = player->trayTiles.tiles[i-1];
|
||||
bits |= (3 << (i-2));
|
||||
}
|
||||
++player->trayTiles.nTiles;
|
||||
player->trayTiles.tiles[index] = tile;
|
||||
} /* addPlayerTile */
|
||||
|
||||
bits |= (1 << index);
|
||||
notifyTrayListeners( model, turn, bits );
|
||||
void
|
||||
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 */
|
||||
|
||||
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
|
||||
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 */
|
||||
|
||||
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 ) {
|
||||
(*model->vol.trayListenerFunc)( model->vol.trayListenerData, turn,
|
||||
bits );
|
||||
index1, index2 );
|
||||
}
|
||||
} /* notifyTrayListeners */
|
||||
|
||||
|
|
|
@ -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 );
|
||||
void model_addPlayerTile( ModelCtxt* model, XP_S16 turn, XP_S16 index,
|
||||
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
|
||||
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_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,
|
||||
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 );
|
||||
|
||||
|
||||
|
@ -184,7 +190,8 @@ typedef void (*BoardListener)(void* data, XP_U16 turn, XP_U16 col,
|
|||
XP_U16 row, XP_Bool added );
|
||||
void model_setBoardListener( ModelCtxt* model, BoardListener bl,
|
||||
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* data );
|
||||
void model_foreachPendingCell( ModelCtxt* model, XP_S16 turn,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* -*-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
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
#include "boardp.h"
|
||||
#include "dragdrpp.h"
|
||||
#include "engine.h"
|
||||
#include "draw.h"
|
||||
#include "strutils.h"
|
||||
|
@ -27,13 +28,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/****************************** 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 drawPendingScore( BoardCtxt* board, XP_Bool hasCursor );
|
||||
static void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
|
||||
XP_U16 tileIndex2 );
|
||||
static XP_Bool endTileDragIndex( BoardCtxt* board, TileBit last );
|
||||
static XP_U16 countTilesToShow( BoardCtxt* board );
|
||||
|
||||
static XP_S16
|
||||
trayLocToIndex( BoardCtxt* board, XP_U16 loc )
|
||||
|
@ -48,7 +45,7 @@ trayLocToIndex( BoardCtxt* board, XP_U16 loc )
|
|||
return loc;
|
||||
} /* trayLocToIndex */
|
||||
|
||||
static XP_S16
|
||||
XP_S16
|
||||
pointToTileIndex( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* onDividerP )
|
||||
{
|
||||
XP_S16 result = -1; /* not on a tile */
|
||||
|
@ -99,11 +96,32 @@ figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect )
|
|||
}
|
||||
} /* 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
|
||||
drawTray( BoardCtxt* board )
|
||||
{
|
||||
XP_Rect tileRect;
|
||||
short i;
|
||||
|
||||
if ( (board->trayInvalBits != 0) || board->dividerInvalid ) {
|
||||
XP_S16 turn = board->selPlayer;
|
||||
|
@ -122,23 +140,23 @@ drawTray( BoardCtxt* board )
|
|||
}
|
||||
#endif
|
||||
|
||||
/* if ( board->eraseTray ) { */
|
||||
/* draw_clearRect( board->draw, &board->trayBounds ); */
|
||||
/* board->eraseTray = XP_FALSE; */
|
||||
/* } */
|
||||
|
||||
if ( (board->trayVisState != TRAY_HIDDEN) && dictionary != NULL ) {
|
||||
XP_Bool showFaces = board->trayVisState == TRAY_REVEALED;
|
||||
Tile blank = dict_getBlankTile( dictionary );
|
||||
|
||||
if ( turn >= 0 ) {
|
||||
XP_U16 numInTray = showFaces?
|
||||
model_getNumTilesInTray( board->model, turn ):
|
||||
model_getNumTilesTotal( board->model, turn );
|
||||
XP_S16 i; /* which tile slot are we drawing in */
|
||||
XP_U16 ddAddedIndx, ddRmvdIndx;
|
||||
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
|
||||
erasing */
|
||||
for ( i = MAX_TRAY_TILES - 1; i >= 0; --i ) {
|
||||
for ( i = MAX_TRAY_TILES - 1;
|
||||
i >= 0; --i ) {
|
||||
CellFlags flags = CELL_NONE;
|
||||
XP_U16 mask = 1 << i;
|
||||
|
||||
|
@ -161,28 +179,41 @@ drawTray( BoardCtxt* board )
|
|||
XP_UCHAR* textP = (XP_UCHAR*)NULL;
|
||||
XP_U8 traySelBits = board->traySelBits[turn];
|
||||
XP_S16 value;
|
||||
Tile tile = model_getPlayerTile( board->model,
|
||||
turn, i );
|
||||
Tile tile;
|
||||
|
||||
if ( dict_faceIsBitmap( dictionary, tile ) ) {
|
||||
bitmap = dict_getFaceBitmap( dictionary, tile,
|
||||
XP_TRUE );
|
||||
if ( ddAddedIndx == i ) {
|
||||
dragDropTileInfo( board, &tile, &isBlank );
|
||||
} else {
|
||||
textP = buf;
|
||||
dict_tilesToString( dictionary, &tile, 1,
|
||||
textP, sizeof(buf) );
|
||||
XP_U16 modIndex = i;
|
||||
if ( ddAddedIndx < i ) {
|
||||
--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
|
||||
&& !board->showCellValues ) {
|
||||
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;
|
||||
}
|
||||
if ( tile == blank ) {
|
||||
if ( isBlank ) {
|
||||
flags |= CELL_ISBLANK;
|
||||
}
|
||||
|
||||
|
@ -199,7 +230,7 @@ drawTray( BoardCtxt* board )
|
|||
XP_Rect divider;
|
||||
figureDividerRect( board, ÷r );
|
||||
draw_drawTrayDivider( board->draw, ÷r,
|
||||
board->divDragState.dragInProgress );
|
||||
dragDropIsDividerDrag(board) );
|
||||
board->dividerInvalid = XP_FALSE;
|
||||
}
|
||||
|
||||
|
@ -216,42 +247,69 @@ drawTray( BoardCtxt* board )
|
|||
|
||||
} /* 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
|
||||
drawPendingScore( BoardCtxt* board, XP_Bool hasCursor )
|
||||
{
|
||||
/* 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 tilesInTray = model_getNumTilesInTray( board->model, selPlayer);
|
||||
if ( tilesInTray < MAX_TRAY_TILES ) {
|
||||
XP_S16 turnScore = 0;
|
||||
XP_Rect lastTileR;
|
||||
|
||||
XP_S16 turnScore = 0;
|
||||
XP_Rect lastTileR;
|
||||
|
||||
(void)getCurrentMoveScoreIfLegal( board->model, selPlayer,
|
||||
(XWStreamCtxt*)NULL, &turnScore );
|
||||
figureTrayTileRect( board, MAX_TRAY_TILES-1, &lastTileR );
|
||||
draw_score_pendingScore( board->draw, &lastTileR, turnScore,
|
||||
selPlayer,
|
||||
hasCursor?CELL_ISCURSOR:CELL_NONE );
|
||||
}
|
||||
(void)getCurrentMoveScoreIfLegal( board->model, selPlayer,
|
||||
(XWStreamCtxt*)NULL, &turnScore );
|
||||
figureTrayTileRect( board, MAX_TRAY_TILES-1, &lastTileR );
|
||||
draw_score_pendingScore( board->draw, &lastTileR, turnScore,
|
||||
selPlayer,
|
||||
hasCursor?CELL_ISCURSOR:CELL_NONE );
|
||||
}
|
||||
} /* 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
|
||||
figureDividerRect( BoardCtxt* board, XP_Rect* rect )
|
||||
{
|
||||
|
@ -293,66 +351,38 @@ handleTrayDuringTrade( BoardCtxt* board, XP_S16 index )
|
|||
} /* handleTrayDuringTrade */
|
||||
|
||||
static XP_Bool
|
||||
handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider,
|
||||
XP_Bool waitPenUp )
|
||||
handleActionInTray( BoardCtxt* board, XP_S16 index, XP_Bool onDivider )
|
||||
{
|
||||
XP_Bool result = XP_FALSE;
|
||||
XP_U16 selPlayer = board->selPlayer;
|
||||
|
||||
if ( onDivider ) {
|
||||
result = startDividerDrag( board );
|
||||
} else if ( board->tradeInProgress[selPlayer]
|
||||
/* && MY_TURN(board) */ ) {
|
||||
/* do nothing */
|
||||
} else if ( board->tradeInProgress[selPlayer] ) {
|
||||
if ( index >= 0 ) {
|
||||
result = handleTrayDuringTrade( board, index );
|
||||
}
|
||||
} else if ( index >= 0 ) {
|
||||
TileBit newIndex = 1 << index;
|
||||
BoardArrow* arrow = &board->boardArrow[selPlayer];
|
||||
|
||||
if ( !arrow->visible ) {
|
||||
XP_U8 selFlags = board->traySelBits[selPlayer];
|
||||
result = moveTileToArrowLoc( board, (XP_U8)index );
|
||||
if ( !result ) {
|
||||
TileBit newBits = 1 << index;
|
||||
XP_U8 selBits = board->traySelBits[selPlayer];
|
||||
/* Tap on selected tile unselects. If we don't do this,
|
||||
then there's no way to unselect and so no way to turn
|
||||
off the placement arrow */
|
||||
if ( !waitPenUp && newIndex == selFlags ) {
|
||||
board_invalTrayTiles( board, selFlags );
|
||||
selFlags = NO_TILES;
|
||||
board->traySelBits[selPlayer] = selFlags;
|
||||
result = XP_TRUE;
|
||||
if ( newBits == selBits ) {
|
||||
board_invalTrayTiles( board, selBits );
|
||||
board->traySelBits[selPlayer] = NO_TILES;
|
||||
} else if ( selBits != 0 ) {
|
||||
XP_U16 selIndex = indexForBits( selBits );
|
||||
model_moveTileOnTray( board->model, board->selPlayer,
|
||||
selIndex, index );
|
||||
board->traySelBits[selPlayer] = NO_TILES;
|
||||
} else {
|
||||
result = startTileDrag( board, newIndex );
|
||||
if ( !waitPenUp ) {
|
||||
/* key interface means pen up and down happen in the same
|
||||
event. No dragging. */
|
||||
result = endTileDragIndex( board, newIndex ) || result;
|
||||
}
|
||||
board_invalTrayTiles( board, newBits );
|
||||
board->traySelBits[selPlayer] = newBits;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 );
|
||||
result = XP_TRUE;
|
||||
}
|
||||
} else if ( index == -(MAX_TRAY_TILES) ) { /* pending score tile */
|
||||
result = board_commitTurn( board );
|
||||
|
@ -361,85 +391,17 @@ handlePenUpTrayInt( BoardCtxt* board, XP_S16 index )
|
|||
(void)board_replaceTiles( board );
|
||||
result = XP_TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* handlePenUpTray */
|
||||
} /* handleActionInTray */
|
||||
|
||||
XP_Bool
|
||||
handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
||||
{
|
||||
XP_Bool ignore;
|
||||
XP_S16 index = pointToTileIndex( board, x, y, &ignore );
|
||||
return handlePenUpTrayInt( board, index );
|
||||
XP_Bool onDivider;
|
||||
XP_S16 index = pointToTileIndex( board, x, y, &onDivider );
|
||||
return handleActionInTray( board, index, onDivider );
|
||||
} /* 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
|
||||
indexForBits( XP_U8 bits )
|
||||
{
|
||||
|
@ -455,123 +417,48 @@ indexForBits( XP_U8 bits )
|
|||
return result;
|
||||
} /* 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
|
||||
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 )
|
||||
{
|
||||
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
|
||||
there's no need to invalidate any tiles to the left of the uppermore
|
||||
divider position. */
|
||||
if ( oldLoc > newLoc ) {
|
||||
--oldLoc;
|
||||
} else {
|
||||
--newLoc;
|
||||
/* 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
|
||||
divider position. */
|
||||
if ( oldLoc > newLoc ) {
|
||||
--oldLoc;
|
||||
} else {
|
||||
--newLoc;
|
||||
}
|
||||
invalTrayTilesBetween( board, newLoc, oldLoc );
|
||||
|
||||
board->dividerInvalid = XP_TRUE;
|
||||
/* changed number of available tiles */
|
||||
board_resetEngine( board );
|
||||
}
|
||||
invalTrayTilesBetween( board, newLoc, oldLoc );
|
||||
|
||||
board->dividerInvalid = XP_TRUE;
|
||||
/* changed number of available tiles */
|
||||
board_resetEngine( board );
|
||||
return moved;
|
||||
} /* 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
|
||||
board_invalTrayTiles( BoardCtxt* board, TileBit what )
|
||||
{
|
||||
board->trayInvalBits |= what;
|
||||
} /* 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,
|
||||
XP_U16 tileIndex2 )
|
||||
{
|
||||
|
@ -710,7 +597,7 @@ board_moveDivider( BoardCtxt* board, XP_Bool right )
|
|||
loc += right? 1:-1;
|
||||
loc %= MAX_TRAY_TILES + 1;
|
||||
|
||||
dividerMoved( board, loc );
|
||||
(void)dividerMoved( board, loc );
|
||||
}
|
||||
return result;
|
||||
} /* board_moveDivider */
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* -*- 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
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -71,7 +72,7 @@ eraseRect( GtkDrawCtx* dctx, const XP_Rect* rect )
|
|||
} /* eraseRect */
|
||||
|
||||
static void
|
||||
frameRect( GtkDrawCtx* dctx, XP_Rect* rect )
|
||||
frameRect( GtkDrawCtx* dctx, const XP_Rect* rect )
|
||||
{
|
||||
gdk_draw_rectangle( DRAW_WHAT(dctx),
|
||||
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 );
|
||||
}
|
||||
|
||||
/* draw the bonus colors only if we're not putting a "tile" there */
|
||||
if ( !!letter ) {
|
||||
if ( *letter == LETTER_NONE && bonus != BONUS_NONE ) {
|
||||
XP_ASSERT( bonus <= 4 );
|
||||
|
||||
/* We draw just an empty, potentially colored, square IFF there's nothing
|
||||
in the cell or if CELL_DRAGSRC is set */
|
||||
if ( (flags & CELL_DRAGSRC) != 0 || ( !!letter && *letter == LETTER_NONE ) ) {
|
||||
if ( bonus != BONUS_NONE ) {
|
||||
gdk_gc_set_foreground( dctx->drawGC, &dctx->bonusColors[bonus-1] );
|
||||
gdk_draw_rectangle( DRAW_WHAT(dctx),
|
||||
dctx->drawGC,
|
||||
TRUE,
|
||||
gdk_draw_rectangle( DRAW_WHAT(dctx), dctx->drawGC, TRUE,
|
||||
rectInset.left, rectInset.top,
|
||||
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 ) {
|
||||
GdkColor* foreground;
|
||||
if ( !highlight ) {
|
||||
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 ) {
|
||||
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 );
|
||||
foreground = highlight? &dctx->white : &dctx->playerColors[owner];
|
||||
draw_string_at( dctx, letter, rectInset.height-2, &rectInset,
|
||||
XP_GTK_JUST_CENTER, foreground, NULL );
|
||||
|
||||
foreground = highlight? &dctx->white : &dctx->playerColors[owner];
|
||||
draw_string_at( dctx, letter, rectInset.height-2,
|
||||
&rectInset, XP_GTK_JUST_CENTER,
|
||||
foreground, NULL );
|
||||
|
||||
if ( (flags & CELL_ISBLANK) != 0 ) {
|
||||
gdk_draw_arc( DRAW_WHAT(dctx), dctx->drawGC,
|
||||
0, /* filled */
|
||||
rect->left, /* x */
|
||||
rect->top, /* y */
|
||||
rect->width,/*width, */
|
||||
rect->height,/*width, */
|
||||
0, 360*64 );
|
||||
}
|
||||
if ( (flags & CELL_ISBLANK) != 0 ) {
|
||||
gdk_draw_arc( DRAW_WHAT(dctx), dctx->drawGC,
|
||||
0, /* filled */
|
||||
rect->left, /* x */
|
||||
rect->top, /* y */
|
||||
rect->width,/*width, */
|
||||
rect->height,/*width, */
|
||||
0, 360*64 );
|
||||
}
|
||||
} else if ( !!bitmap ) {
|
||||
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 );
|
||||
|
||||
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 */
|
||||
|
||||
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( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
|
||||
XP_Bitmap bitmap, XP_S16 val, CellFlags flags,
|
||||
XP_Bool clearBack )
|
||||
{
|
||||
XP_UCHAR numbuf[3];
|
||||
gint len;
|
||||
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
|
||||
XP_Rect insetR = *rect;
|
||||
|
||||
eraseRect( dctx, &insetR );
|
||||
if ( clearBack ) {
|
||||
eraseRect( dctx, &insetR );
|
||||
}
|
||||
|
||||
if ( val >= 0 ) {
|
||||
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 );
|
||||
|
||||
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.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 != LETTER_NONE ) { /* blank */
|
||||
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 */
|
||||
|
||||
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
|
||||
gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect,
|
||||
CellFlags flags )
|
||||
|
@ -635,7 +650,7 @@ gtk_draw_drawTrayDivider( DrawCtx* p_dctx, const XP_Rect* rect,
|
|||
++r.left;
|
||||
r.width -= selected? 2:1;
|
||||
if ( selected ) {
|
||||
--r.height;
|
||||
--r.height;
|
||||
}
|
||||
|
||||
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_drawTile, 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_drawBoardArrow, gtk );
|
||||
|
|
|
@ -108,12 +108,13 @@ button_press_event( GtkWidget* XP_UNUSED(widget), GdkEventButton *event,
|
|||
{
|
||||
XP_Bool redraw, handled;
|
||||
|
||||
globals->mouseDown = XP_TRUE;
|
||||
|
||||
redraw = board_handlePenDown( globals->cGlobals.game.board,
|
||||
if ( !globals->mouseDown ) {
|
||||
globals->mouseDown = XP_TRUE;
|
||||
redraw = board_handlePenDown( globals->cGlobals.game.board,
|
||||
event->x, event->y, &handled );
|
||||
if ( redraw ) {
|
||||
board_draw( globals->cGlobals.game.board );
|
||||
if ( redraw ) {
|
||||
board_draw( globals->cGlobals.game.board );
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
} /* button_press_event */
|
||||
|
|
Loading…
Add table
Reference in a new issue