mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-15 15:41:24 +01:00
break board.c up so isn't too large for 68K on palm when compiled for
debugging.
This commit is contained in:
parent
bc05761c4a
commit
0d44c26373
4 changed files with 596 additions and 505 deletions
|
@ -72,18 +72,9 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
/****************************** prototypes ******************************/
|
||||
static XP_Bool getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
XP_Rect* rect);
|
||||
static XP_Bool drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
XP_Bool skipBlanks );
|
||||
static void figureBoardRect( BoardCtxt* board );
|
||||
static void forceRectToBoard( const BoardCtxt* board, XP_Rect* rect );
|
||||
|
||||
static void drawBoard( BoardCtxt* board );
|
||||
static void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
static void invalCellsUnderRect( BoardCtxt* board,
|
||||
const XP_Rect* rect );
|
||||
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 boardTilesChanged( void* board, XP_U16 turn, XP_S16 index1,
|
||||
|
@ -95,11 +86,7 @@ static void setArrowFor( BoardCtxt* board, XP_U16 player, XP_U16 col,
|
|||
XP_U16 row );
|
||||
static XP_Bool setArrowVisible( BoardCtxt* board, XP_Bool visible );
|
||||
|
||||
static void makeMiniWindowForTrade( BoardCtxt* board );
|
||||
static void makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
|
||||
MiniWindowType winType );
|
||||
static void invalTradeWindow( BoardCtxt* board, XP_S16 turn, XP_Bool redraw );
|
||||
static void invalSelTradeWindow( BoardCtxt* board );
|
||||
static void setTimerIf( BoardCtxt* board );
|
||||
static XP_Bool p_board_timerFired( void* closure, XWTimerReason why );
|
||||
|
||||
|
@ -112,9 +99,6 @@ 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 );
|
||||
#ifdef POINTER_SUPPORT
|
||||
static void drawDragTileIf( BoardCtxt* board );
|
||||
#endif
|
||||
|
||||
#ifdef KEY_SUPPORT
|
||||
static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey,
|
||||
|
@ -130,7 +114,6 @@ static XP_Bool invalFocusOwner( BoardCtxt* board );
|
|||
# define invalFocusOwner(board)
|
||||
#endif
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
static void clearCurHintRect( BoardCtxt* board );
|
||||
|
||||
#else
|
||||
|
@ -524,7 +507,7 @@ invalTradeWindow( BoardCtxt* board, XP_S16 turn, XP_Bool redraw )
|
|||
}
|
||||
} /* invalTradeWindow */
|
||||
|
||||
static void
|
||||
void
|
||||
invalSelTradeWindow( BoardCtxt* board )
|
||||
{
|
||||
invalTradeWindow( board, board->selPlayer,
|
||||
|
@ -926,30 +909,6 @@ board_invalAllTiles( BoardCtxt* board )
|
|||
|
||||
#ifdef KEYBOARD_NAV
|
||||
#ifdef PERIMETER_FOCUS
|
||||
static void
|
||||
invalOldPerimeter( BoardCtxt* board )
|
||||
{
|
||||
/* We need to inval the center of the row that's moving into the center
|
||||
from a border (at which point it got borders drawn on it.) */
|
||||
XP_S16 diff = board->yOffset - board->prevYScrollOffset;
|
||||
XP_U16 firstRow, lastRow;
|
||||
XP_ASSERT( diff != 0 );
|
||||
if ( diff < 0 ) {
|
||||
/* moving up; inval row previously on bottom */
|
||||
firstRow = board->yOffset + 1;
|
||||
lastRow = board->prevYScrollOffset;
|
||||
} else {
|
||||
XP_U16 nVisible = board->lastVisibleRow - board->yOffset + 1;
|
||||
lastRow = board->prevYScrollOffset + nVisible - 1;
|
||||
firstRow = lastRow - diff + 1;
|
||||
}
|
||||
XP_ASSERT( firstRow <= lastRow );
|
||||
while ( firstRow <= lastRow ) {
|
||||
board->redrawFlags[firstRow] |= ~0;
|
||||
++firstRow;
|
||||
}
|
||||
} /* invalOldPerimeter */
|
||||
|
||||
static void
|
||||
invalPerimeter( BoardCtxt* board )
|
||||
{
|
||||
|
@ -1059,9 +1018,9 @@ checkScrollCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
|||
if ( board->boardObscuresTray && board->trayVisState != TRAY_HIDDEN ) {
|
||||
/* call getCellRect until the cell's on the board. */
|
||||
while ( !getCellRect( board, col, row, &rect ) ) {
|
||||
XP_S16 moveBy;
|
||||
XP_S16 moveBy = 1;
|
||||
if ( rect.top < board->boardBounds.top ) {
|
||||
moveBy = 1;
|
||||
/* do nothing; set to 1 above to prevent warning */
|
||||
} else if ( rect.top + rect.height >
|
||||
board->boardBounds.top + board->boardBounds.height ) {
|
||||
moveBy = -1;
|
||||
|
@ -1096,245 +1055,6 @@ onBorderCanScroll( const BoardCtxt* board, XP_U16 row, XP_S16* changeP )
|
|||
return result;
|
||||
}
|
||||
|
||||
/* if any of a blank's neighbors is invalid, so must the blank become (since
|
||||
* they share a border and drawing the neighbor will redraw the blank's border
|
||||
* too) We'll want to redraw only those blanks that are themselves already
|
||||
* invalid *OR* that become invalid this way, and so we'll build a new
|
||||
* BlankQueue of them and replace the old.
|
||||
*
|
||||
* I'm not sure what happens if two blanks are neighbors.
|
||||
*/
|
||||
#define INVAL_BIT_SET(b,c,r) (((b)->redrawFlags[(r)] & (1 <<(c))) != 0)
|
||||
static void
|
||||
invalBlanksWithNeighbors( BoardCtxt* board, BlankQueue* bqp )
|
||||
{
|
||||
XP_U16 i;
|
||||
XP_U16 lastCol, lastRow;
|
||||
BlankQueue invalBlanks;
|
||||
XP_U16 nInvalBlanks = 0;
|
||||
|
||||
lastCol = model_numCols(board->model) - 1;
|
||||
lastRow = model_numRows(board->model) - 1;
|
||||
|
||||
for ( i = 0; i < bqp->nBlanks; ++i ) {
|
||||
XP_U16 modelCol = bqp->col[i];
|
||||
XP_U16 modelRow = bqp->row[i];
|
||||
XP_U16 col, row;
|
||||
|
||||
flipIf( board, modelCol, modelRow, &col, &row );
|
||||
|
||||
if ( INVAL_BIT_SET( board, col, row )
|
||||
|| (col > 0 && INVAL_BIT_SET( board, col-1, row ))
|
||||
|| (col < lastCol && INVAL_BIT_SET( board, col+1, row ))
|
||||
|| (row > 0 && INVAL_BIT_SET( board, col, row-1 ))
|
||||
|| (row < lastRow && INVAL_BIT_SET( board, col, row+1 )) ) {
|
||||
|
||||
invalCell( board, col, row );
|
||||
|
||||
invalBlanks.col[nInvalBlanks] = (XP_U8)col;
|
||||
invalBlanks.row[nInvalBlanks] = (XP_U8)row;
|
||||
++nInvalBlanks;
|
||||
}
|
||||
}
|
||||
invalBlanks.nBlanks = nInvalBlanks;
|
||||
XP_MEMCPY( bqp, &invalBlanks, sizeof(*bqp) );
|
||||
} /* invalBlanksWithNeighbors */
|
||||
|
||||
static void
|
||||
scrollIfCan( BoardCtxt* board )
|
||||
{
|
||||
if ( board->yOffset != board->prevYScrollOffset ) {
|
||||
XP_Rect scrollR = board->boardBounds;
|
||||
XP_Bool scrolled;
|
||||
XP_S16 dist;
|
||||
|
||||
#ifdef PERIMETER_FOCUS
|
||||
if ( (board->focussed == OBJ_BOARD) && !board->focusHasDived ) {
|
||||
invalOldPerimeter( board );
|
||||
}
|
||||
#endif
|
||||
invalSelTradeWindow( board );
|
||||
dist = (board->yOffset - board->prevYScrollOffset)
|
||||
* board->boardVScale;
|
||||
|
||||
scrolled = draw_vertScrollBoard( board->draw, &scrollR, dist,
|
||||
dfsFor( board, OBJ_BOARD ) );
|
||||
|
||||
if ( scrolled ) {
|
||||
/* inval the rows that have been scrolled into view. I'm cheating
|
||||
making the client figure the inval rect, but Palm's the first
|
||||
client and it does it so well.... */
|
||||
invalCellsUnderRect( board, &scrollR );
|
||||
} else {
|
||||
board_invalAll( board );
|
||||
}
|
||||
board->prevYScrollOffset = board->yOffset;
|
||||
}
|
||||
} /* scrollIfCan */
|
||||
|
||||
static void
|
||||
drawTradeWindowIf( BoardCtxt* board )
|
||||
{
|
||||
if ( board->tradingMiniWindowInvalid &&
|
||||
TRADE_IN_PROGRESS(board) && board->trayVisState == TRAY_REVEALED ) {
|
||||
MiniWindowStuff* stuff;
|
||||
|
||||
makeMiniWindowForTrade( board );
|
||||
|
||||
stuff = &board->miniWindowStuff[MINIWINDOW_TRADING];
|
||||
draw_drawMiniWindow( board->draw, stuff->text,
|
||||
&stuff->rect, (void**)NULL );
|
||||
|
||||
board->tradingMiniWindowInvalid = XP_FALSE;
|
||||
}
|
||||
} /* drawTradeWindowIf */
|
||||
|
||||
XP_Bool
|
||||
board_draw( BoardCtxt* board )
|
||||
{
|
||||
if ( board->boardBounds.width > 0 ) {
|
||||
|
||||
drawScoreBoard( board );
|
||||
|
||||
drawTray( board );
|
||||
|
||||
drawBoard( board );
|
||||
}
|
||||
return !board->needsDrawing;
|
||||
} /* board_draw */
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
static XP_Bool
|
||||
cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row )
|
||||
{
|
||||
XP_Bool focussed = XP_FALSE;
|
||||
|
||||
if ( board->focussed == OBJ_BOARD ) {
|
||||
if ( board->focusHasDived ) {
|
||||
if ( (col == board->bdCursor[board->selPlayer].col)
|
||||
&& (row == board->bdCursor[board->selPlayer].row) ) {
|
||||
focussed = XP_TRUE;
|
||||
}
|
||||
} else {
|
||||
#ifdef PERIMETER_FOCUS
|
||||
focussed = (col == 0)
|
||||
|| (col == model_numCols(board->model) - 1)
|
||||
|| (row == board->yOffset)
|
||||
|| (row == board->lastVisibleRow);
|
||||
#else
|
||||
focussed = XP_TRUE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return focussed;
|
||||
} /* cellFocused */
|
||||
#endif
|
||||
|
||||
static void
|
||||
drawBoard( BoardCtxt* board )
|
||||
{
|
||||
if ( board->needsDrawing
|
||||
&& draw_boardBegin( board->draw,
|
||||
model_getDictionary( board->model ),
|
||||
&board->boardBounds,
|
||||
dfsFor( board, OBJ_BOARD ) ) ) {
|
||||
|
||||
XP_Bool allDrawn = XP_TRUE;
|
||||
XP_S16 lastCol, i;
|
||||
XP_S16 row;
|
||||
ModelCtxt* model = board->model;
|
||||
BlankQueue bq;
|
||||
XP_Rect arrowRect;
|
||||
|
||||
scrollIfCan( board ); /* this must happen before we count blanks
|
||||
since it invalidates squares */
|
||||
|
||||
/* This is freaking expensive!!!! PENDING FIXME Can't we start from
|
||||
what's invalid rather than scanning the entire model every time
|
||||
somebody dirties a single cell? */
|
||||
model_listPlacedBlanks( model, board->selPlayer,
|
||||
board->trayVisState == TRAY_REVEALED, &bq );
|
||||
invalBlanksWithNeighbors( board, &bq );
|
||||
|
||||
for ( row = board->yOffset; row <= board->lastVisibleRow; ++row ) {
|
||||
XP_U16 rowFlags = board->redrawFlags[row];
|
||||
if ( rowFlags != 0 ) {
|
||||
XP_U16 colMask;
|
||||
XP_U16 failedBits = 0;
|
||||
lastCol = model_numCols( model );
|
||||
for ( colMask = 1<<(lastCol-1); lastCol--; colMask >>= 1 ) {
|
||||
if ( (rowFlags & colMask) != 0 ) {
|
||||
if ( !drawCell( board, lastCol, row, XP_TRUE )) {
|
||||
failedBits |= colMask;
|
||||
allDrawn = XP_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
board->redrawFlags[row] = failedBits;
|
||||
}
|
||||
}
|
||||
|
||||
/* draw the blanks we skipped before */
|
||||
for ( i = 0; i < bq.nBlanks; ++i ) {
|
||||
if ( !drawCell( board, bq.col[i], bq.row[i], XP_FALSE ) ) {
|
||||
allDrawn = XP_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( board->trayVisState == TRAY_REVEALED ) {
|
||||
BoardArrow* arrow = &board->boardArrow[board->selPlayer];
|
||||
|
||||
if ( arrow->visible ) {
|
||||
XP_U16 col = arrow->col;
|
||||
XP_U16 row = arrow->row;
|
||||
if ( getCellRect( board, col, row, &arrowRect ) ) {
|
||||
XWBonusType bonus;
|
||||
HintAtts hintAtts;
|
||||
CellFlags flags = CELL_NONE;
|
||||
bonus = util_getSquareBonus( board->util, model,
|
||||
col, row );
|
||||
hintAtts = figureHintAtts( board, col, row );
|
||||
#ifdef KEYBOARD_NAV
|
||||
if ( cellFocused( board, col, row ) ) {
|
||||
flags |= CELL_ISCURSOR;
|
||||
}
|
||||
#endif
|
||||
draw_drawBoardArrow( board->draw, &arrowRect, bonus,
|
||||
arrow->vert, hintAtts, flags );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 ) );
|
||||
|
||||
board->needsDrawing = !allDrawn;
|
||||
}
|
||||
} /* drawBoard */
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
DrawFocusState
|
||||
dfsFor( BoardCtxt* board, BoardObjectType obj )
|
||||
{
|
||||
DrawFocusState dfs;
|
||||
if ( board->focussed == obj ) {
|
||||
if ( board->focusHasDived ) {
|
||||
dfs = DFS_DIVED;
|
||||
} else {
|
||||
dfs = DFS_TOP;
|
||||
}
|
||||
} else {
|
||||
dfs = DFS_NONE;
|
||||
}
|
||||
return dfs;
|
||||
} /* dfsFor */
|
||||
#endif
|
||||
|
||||
void
|
||||
board_setTrayLoc( BoardCtxt* board, XP_U16 trayLeft, XP_U16 trayTop,
|
||||
XP_U16 trayWidth, XP_U16 trayHeight,
|
||||
|
@ -1387,7 +1107,7 @@ board_setTrayLoc( BoardCtxt* board, XP_U16 trayLeft, XP_U16 trayTop,
|
|||
figureBoardRect( board );
|
||||
} /* board_setTrayLoc */
|
||||
|
||||
static void
|
||||
void
|
||||
invalCellsUnderRect( BoardCtxt* board, const XP_Rect* rect )
|
||||
{
|
||||
XP_Rect lr = *rect;
|
||||
|
@ -1777,108 +1497,6 @@ board_requestHint( BoardCtxt* board,
|
|||
return result || redraw;
|
||||
} /* board_requestHint */
|
||||
|
||||
static XP_Bool
|
||||
drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks )
|
||||
{
|
||||
XP_Bool success = XP_TRUE;
|
||||
XP_Rect cellRect;
|
||||
Tile tile;
|
||||
XP_Bool isBlank, isEmpty, recent, pending = XP_FALSE;
|
||||
XWBonusType bonus;
|
||||
ModelCtxt* model = board->model;
|
||||
DictionaryCtxt* dict = model_getDictionary( model );
|
||||
XP_U16 modelCol, modelRow;
|
||||
|
||||
if ( dict != NULL && getCellRect( board, col, row, &cellRect ) ) {
|
||||
|
||||
/* We want to invert EITHER the current pending tiles OR the most recent
|
||||
* move. So if the tray is visible AND there are tiles missing from it,
|
||||
* show them. Otherwise show the most recent move.
|
||||
*/
|
||||
XP_U16 selPlayer = board->selPlayer;
|
||||
XP_U16 curCount = model_getCurrentMoveCount( model, selPlayer );
|
||||
XP_Bool showPending = board->trayVisState == TRAY_REVEALED
|
||||
&& curCount > 0;
|
||||
|
||||
flipIf( board, col, row, &modelCol, &modelRow );
|
||||
|
||||
/* This 'while' is only here so I can 'break' below */
|
||||
while ( board->trayVisState == TRAY_HIDDEN ||
|
||||
!rectContainsRect( &board->trayBounds, &cellRect ) ) {
|
||||
XP_UCHAR ch[4] = {'\0'};
|
||||
XP_S16 owner = -1;
|
||||
XP_Bool invert = XP_FALSE;
|
||||
XP_Bitmap bitmap = NULL;
|
||||
XP_UCHAR* textP = NULL;
|
||||
HintAtts hintAtts;
|
||||
CellFlags flags = CELL_NONE;
|
||||
XP_Bool isOrigin;
|
||||
|
||||
isEmpty = !model_getTile( model, modelCol, modelRow, showPending,
|
||||
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;
|
||||
flags |= CELL_ISEMPTY;
|
||||
} else if ( isBlank && skipBlanks ) {
|
||||
break;
|
||||
} else {
|
||||
if ( board->showColors ) {
|
||||
owner = (XP_S16)model_getCellOwner( model, modelCol,
|
||||
modelRow );
|
||||
}
|
||||
|
||||
invert = showPending? pending : recent;
|
||||
|
||||
if ( board->showCellValues ) {
|
||||
Tile valTile = isBlank? dict_getBlankTile( dict ) : tile;
|
||||
XP_U16 val = dict_getTileValue( dict, valTile );
|
||||
XP_SNPRINTF( ch, sizeof(ch), (XP_UCHAR*)"%d", val );
|
||||
textP = ch;
|
||||
} else if ( dict_faceIsBitmap( dict, tile ) ) {
|
||||
bitmap = dict_getFaceBitmap( dict, tile, XP_FALSE );
|
||||
XP_ASSERT( !!bitmap );
|
||||
} else {
|
||||
(void)dict_tilesToString( dict, &tile, 1, ch, sizeof(ch) );
|
||||
textP = ch;
|
||||
}
|
||||
}
|
||||
bonus = util_getSquareBonus( board->util, model, col, row );
|
||||
hintAtts = figureHintAtts( board, col, row );
|
||||
|
||||
if ( (col==board->star_row) && (row==board->star_row) ) {
|
||||
flags |= CELL_ISSTAR;
|
||||
}
|
||||
if ( invert ) {
|
||||
flags |= CELL_HIGHLIGHT;
|
||||
}
|
||||
if ( isBlank ) {
|
||||
flags |= CELL_ISBLANK;
|
||||
}
|
||||
#ifdef KEYBOARD_NAV
|
||||
if ( cellFocused( board, col, row ) ) {
|
||||
flags |= CELL_ISCURSOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
success = draw_drawCell( board->draw, &cellRect, textP, bitmap,
|
||||
tile, owner, bonus, hintAtts, flags );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
} /* drawCell */
|
||||
|
||||
static void
|
||||
figureBoardRect( BoardCtxt* board )
|
||||
{
|
||||
|
@ -1942,7 +1560,7 @@ coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP, XP_U16* rowP )
|
|||
return onBoard;
|
||||
} /* coordToCell */
|
||||
|
||||
static XP_Bool
|
||||
XP_Bool
|
||||
getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Rect* rect )
|
||||
{
|
||||
XP_S16 top;
|
||||
|
@ -1965,7 +1583,7 @@ getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Rect* rect )
|
|||
return onBoard;
|
||||
} /* getCellRect */
|
||||
|
||||
static void
|
||||
void
|
||||
invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
||||
{
|
||||
board->redrawFlags[row] |= 1 << col;
|
||||
|
@ -2033,7 +1651,7 @@ moveTileToArrowLoc( BoardCtxt* board, XP_U8 index )
|
|||
} /* moveTileToArrowLoc */
|
||||
#endif
|
||||
|
||||
static void
|
||||
void
|
||||
makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
|
||||
MiniWindowType winType )
|
||||
{
|
||||
|
@ -2048,16 +1666,6 @@ makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
|
|||
stuff->text = text;
|
||||
} /* makeMiniWindowForText */
|
||||
|
||||
static void
|
||||
makeMiniWindowForTrade( BoardCtxt* board )
|
||||
{
|
||||
const XP_UCHAR* text;
|
||||
|
||||
text = draw_getMiniWText( board->draw, INTRADE_MW_TEXT );
|
||||
|
||||
makeMiniWindowForText( board, text, MINIWINDOW_TRADING );
|
||||
} /* makeMiniWindowForTrade */
|
||||
|
||||
XP_Bool
|
||||
board_beginTrade( BoardCtxt* board )
|
||||
{
|
||||
|
@ -2091,49 +1699,6 @@ ptOnTradeWindow( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
|||
} /* ptOnTradeWindow */
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
static HintAtts
|
||||
figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
||||
{
|
||||
HintAtts result = HINT_BORDER_NONE;
|
||||
|
||||
/* while lets us break to exit... */
|
||||
while ( board->trayVisState == TRAY_REVEALED && board->gi->allowHintRect ) {
|
||||
BdHintLimits limits;
|
||||
if ( dragDropGetHintLimits( board, &limits ) ) {
|
||||
/* do nothing */
|
||||
} else if ( board->hasHintRect[board->selPlayer] ) {
|
||||
limits = board->limits[board->selPlayer];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( col < limits.left ) break;
|
||||
if ( row < limits.top ) break;
|
||||
if ( col > limits.right ) break;
|
||||
if ( row > limits.bottom ) break;
|
||||
|
||||
if ( col == limits.left ) {
|
||||
result |= HINT_BORDER_LEFT;
|
||||
}
|
||||
if ( col == limits.right ) {
|
||||
result |= HINT_BORDER_RIGHT;
|
||||
}
|
||||
if ( row == limits.top) {
|
||||
result |= HINT_BORDER_TOP;
|
||||
}
|
||||
if ( row == limits.bottom ) {
|
||||
result |= HINT_BORDER_BOTTOM;
|
||||
}
|
||||
#ifndef XWFEATURE_SEARCHLIMIT_DOCENTERS
|
||||
if ( result == HINT_BORDER_NONE ) {
|
||||
result = HINT_BORDER_CENTER;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* figureHintAtts */
|
||||
|
||||
void
|
||||
invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
|
||||
|
@ -2494,7 +2059,7 @@ exitTradeMode( BoardCtxt* board )
|
|||
|
||||
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV
|
||||
static XP_Bool
|
||||
handlePenUpInternal( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool isPen )
|
||||
handlePenUpInternal( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool isPen )
|
||||
{
|
||||
XP_Bool draw = XP_FALSE;
|
||||
XP_Bool dragged = XP_FALSE;
|
||||
|
@ -2506,7 +2071,7 @@ handlePenUpInternal( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool isPen )
|
|||
board->penDownObject = OBJ_NONE;
|
||||
|
||||
if ( dragDropInProgress(board) ) {
|
||||
draw = dragDropEnd( board, x, y, &dragged );
|
||||
draw = dragDropEnd( board, xx, yy, &dragged );
|
||||
}
|
||||
if ( dragged ) {
|
||||
/* do nothing further */
|
||||
|
@ -2519,19 +2084,19 @@ handlePenUpInternal( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool isPen )
|
|||
board->penTimerFired = XP_FALSE;
|
||||
} else {
|
||||
BoardObjectType onWhich;
|
||||
if ( pointOnSomething( board, x, y, &onWhich ) ) {
|
||||
if ( pointOnSomething( board, xx, yy, &onWhich ) ) {
|
||||
|
||||
switch( onWhich ) {
|
||||
case OBJ_SCORE:
|
||||
if ( prevObj == OBJ_SCORE ) {
|
||||
draw = handlePenUpScore( board, x, y ) || draw;
|
||||
draw = handlePenUpScore( board, xx, yy ) || draw;
|
||||
}
|
||||
break;
|
||||
case OBJ_BOARD:
|
||||
if ( prevObj == OBJ_BOARD && checkRevealTray(board) ) {
|
||||
|
||||
if ( TRADE_IN_PROGRESS(board) ) {
|
||||
if ( ptOnTradeWindow( board, x, y )) {
|
||||
if ( ptOnTradeWindow( board, xx, yy )) {
|
||||
draw = exitTradeMode( board ) || draw;
|
||||
}
|
||||
} else {
|
||||
|
@ -2547,7 +2112,7 @@ handlePenUpInternal( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool isPen )
|
|||
if ( board->trayVisState == TRAY_REVERSED ) {
|
||||
draw = askRevealTray( board ) || draw;
|
||||
} else {
|
||||
draw = handlePenUpTray( board, x, y ) || draw;
|
||||
draw = handlePenUpTray( board, xx, yy ) || draw;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -2567,7 +2132,7 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
|
|||
#endif /* #ifdef POINTER_SUPPORT */
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
static void
|
||||
void
|
||||
getRectCenter( const XP_Rect* rect, XP_U16* xp, XP_U16* yp )
|
||||
{
|
||||
*xp = rect->left + ( rect->width >> 1 );
|
||||
|
@ -2585,15 +2150,6 @@ getFocussedCellCenter( BoardCtxt* board, XP_U16* xp, XP_U16* yp )
|
|||
getRectCenter( &rect, xp, yp );
|
||||
}
|
||||
|
||||
static void
|
||||
getFocussedTileCenter( BoardCtxt* board, XP_U16* xp, XP_U16* yp )
|
||||
{
|
||||
XP_Rect rect;
|
||||
XP_U16 indx = board->trayCursorLoc[board->selPlayer];
|
||||
figureTrayTileRect( board, indx, &rect );
|
||||
getRectCenter( &rect, xp, yp );
|
||||
}
|
||||
|
||||
static void
|
||||
getFocussedScoreCenter( BoardCtxt* board, XP_U16* xp, XP_U16* yp )
|
||||
{
|
||||
|
@ -2642,7 +2198,7 @@ handleFocusKeyUp( BoardCtxt* board, XP_Key key, XP_Bool preflightOnly,
|
|||
redraw = board_moveCursor( board, key, preflightOnly, &up );
|
||||
} else if ( board->focussed == OBJ_SCORE ) {
|
||||
redraw = moveScoreCursor( board, key, preflightOnly, &up );
|
||||
} else if ( board->focussed == OBJ_TRAY && checkRevealTray(board) ) {
|
||||
} else if ( board->focussed == OBJ_TRAY/* && checkRevealTray(board)*/ ) {
|
||||
redraw = tray_moveCursor( board, key, preflightOnly, &up );
|
||||
}
|
||||
if ( up ) {
|
||||
|
@ -3050,15 +2606,6 @@ board_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool preflightOnly,
|
|||
} /* board_moveCursor */
|
||||
#endif
|
||||
|
||||
static XP_Bool
|
||||
rectContainsRect( XP_Rect* rect1, XP_Rect* rect2 )
|
||||
{
|
||||
return ( rect1->top <= rect2->top
|
||||
&& rect1->left <= rect2->left
|
||||
&& rect1->top + rect1->height >= rect2->top + rect2->height
|
||||
&& rect1->left + rect1->width >= rect2->left + rect2->width );
|
||||
} /* rectContainsRect */
|
||||
|
||||
XP_Bool
|
||||
rectContainsPt( XP_Rect* rect, XP_S16 x, XP_S16 y )
|
||||
{
|
||||
|
@ -3366,7 +2913,7 @@ forceRectToBoard( const BoardCtxt* board, XP_Rect* rect )
|
|||
}
|
||||
} /* forceRectToBoard */
|
||||
|
||||
static void
|
||||
void
|
||||
getDragCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Rect* rectP )
|
||||
{
|
||||
XP_Rect rect;
|
||||
|
@ -3386,40 +2933,6 @@ getDragCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Rect* rectP )
|
|||
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,
|
||||
board->selPlayer, flags );
|
||||
}
|
||||
}
|
||||
} /* drawDragTileIf */
|
||||
#endif
|
||||
|
||||
void
|
||||
invalDragObj( BoardCtxt* board, const DragObjInfo* di )
|
||||
{
|
||||
|
|
561
xwords4/common/boarddrw.c
Normal file
561
xwords4/common/boarddrw.c
Normal file
|
@ -0,0 +1,561 @@
|
|||
/* -*-mode: C; fill-column: 78; compile-command: "cd ../linux && make MEMDEBUG=TRUE"; -*- */
|
||||
/*
|
||||
* 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
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* Re: boards that can't fit on the screen. Let's have an assumption, that
|
||||
* the tray is always either below the board or overlapping its bottom. There
|
||||
* is never any board visible below the tray. But it's possible to have a
|
||||
* board small enough that scrolling is necessary even with the tray hidden.
|
||||
*
|
||||
* Currently we don't specify the board bounds. We give top,left and the size
|
||||
* of cells, and the board figures out the bounds. That's probably a mistake.
|
||||
* Better to give bounds, and maybe a min scale, and let it figure out how
|
||||
* many cells can be visible. Could it also decide if the tray should overlap
|
||||
* or be below? Some platforms have to own that decision since the tray is
|
||||
* narrower than the board. So give them separate bounds-setting functions,
|
||||
* and let the board code figure out if they overlap.
|
||||
*
|
||||
* Problem: the board size must always be a multiple of the scale. The
|
||||
* platform-specific code has an easy time doing that math. The board can't:
|
||||
* it'd have to take bounds, then spit them back out slightly modified. It'd
|
||||
* also have to refuse to work (maybe just assert) if asked to take bounds
|
||||
* before it had a min_scale.
|
||||
*
|
||||
* Another way of looking at it closer to the current: the board's position
|
||||
* and the tray's bounds determine the board's bounds. If the board's vScale
|
||||
* times the number of rows places its would-be bottom at or above the bottom
|
||||
* of the tray, then it's potentially visible. If its would-be bottom is
|
||||
* above the top of the tray, no scrolling is needed. But if it's below the
|
||||
* tray entirely then scrolling will happen even with the tray hidden. As
|
||||
* above, we assume the board never appears below the tray.
|
||||
*/
|
||||
|
||||
#include "comtypes.h"
|
||||
#include "board.h"
|
||||
#include "scorebdp.h"
|
||||
#include "game.h"
|
||||
#include "server.h"
|
||||
#include "comms.h" /* for CHANNEL_NONE */
|
||||
#include "dictnry.h"
|
||||
#include "draw.h"
|
||||
#include "engine.h"
|
||||
#include "util.h"
|
||||
#include "mempool.h" /* debug only */
|
||||
#include "memstream.h"
|
||||
#include "strutils.h"
|
||||
#include "LocalizedStrIncludes.h"
|
||||
|
||||
#include "boardp.h"
|
||||
#include "dragdrpp.h"
|
||||
#include "dbgutil.h"
|
||||
|
||||
#ifdef CPLUS
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static XP_Bool drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
XP_Bool skipBlanks );
|
||||
static void drawBoard( BoardCtxt* board );
|
||||
static void scrollIfCan( BoardCtxt* board );
|
||||
static XP_Bool cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
static void drawTradeWindowIf( BoardCtxt* board );
|
||||
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
#else
|
||||
# define figureHintAtts(b,c,r) HINT_BORDER_NONE
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef POINTER_SUPPORT
|
||||
static void drawDragTileIf( BoardCtxt* board );
|
||||
#endif
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
#ifdef PERIMETER_FOCUS
|
||||
static void
|
||||
invalOldPerimeter( BoardCtxt* board )
|
||||
{
|
||||
/* We need to inval the center of the row that's moving into the center
|
||||
from a border (at which point it got borders drawn on it.) */
|
||||
XP_S16 diff = board->yOffset - board->prevYScrollOffset;
|
||||
XP_U16 firstRow, lastRow;
|
||||
XP_ASSERT( diff != 0 );
|
||||
if ( diff < 0 ) {
|
||||
/* moving up; inval row previously on bottom */
|
||||
firstRow = board->yOffset + 1;
|
||||
lastRow = board->prevYScrollOffset;
|
||||
} else {
|
||||
XP_U16 nVisible = board->lastVisibleRow - board->yOffset + 1;
|
||||
lastRow = board->prevYScrollOffset + nVisible - 1;
|
||||
firstRow = lastRow - diff + 1;
|
||||
}
|
||||
XP_ASSERT( firstRow <= lastRow );
|
||||
while ( firstRow <= lastRow ) {
|
||||
board->redrawFlags[firstRow] |= ~0;
|
||||
++firstRow;
|
||||
}
|
||||
} /* invalOldPerimeter */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* if any of a blank's neighbors is invalid, so must the blank become (since
|
||||
* they share a border and drawing the neighbor will redraw the blank's border
|
||||
* too) We'll want to redraw only those blanks that are themselves already
|
||||
* invalid *OR* that become invalid this way, and so we'll build a new
|
||||
* BlankQueue of them and replace the old.
|
||||
*
|
||||
* I'm not sure what happens if two blanks are neighbors.
|
||||
*/
|
||||
#define INVAL_BIT_SET(b,c,r) (((b)->redrawFlags[(r)] & (1 <<(c))) != 0)
|
||||
static void
|
||||
invalBlanksWithNeighbors( BoardCtxt* board, BlankQueue* bqp )
|
||||
{
|
||||
XP_U16 i;
|
||||
XP_U16 lastCol, lastRow;
|
||||
BlankQueue invalBlanks;
|
||||
XP_U16 nInvalBlanks = 0;
|
||||
|
||||
lastCol = model_numCols(board->model) - 1;
|
||||
lastRow = model_numRows(board->model) - 1;
|
||||
|
||||
for ( i = 0; i < bqp->nBlanks; ++i ) {
|
||||
XP_U16 modelCol = bqp->col[i];
|
||||
XP_U16 modelRow = bqp->row[i];
|
||||
XP_U16 col, row;
|
||||
|
||||
flipIf( board, modelCol, modelRow, &col, &row );
|
||||
|
||||
if ( INVAL_BIT_SET( board, col, row )
|
||||
|| (col > 0 && INVAL_BIT_SET( board, col-1, row ))
|
||||
|| (col < lastCol && INVAL_BIT_SET( board, col+1, row ))
|
||||
|| (row > 0 && INVAL_BIT_SET( board, col, row-1 ))
|
||||
|| (row < lastRow && INVAL_BIT_SET( board, col, row+1 )) ) {
|
||||
|
||||
invalCell( board, col, row );
|
||||
|
||||
invalBlanks.col[nInvalBlanks] = (XP_U8)col;
|
||||
invalBlanks.row[nInvalBlanks] = (XP_U8)row;
|
||||
++nInvalBlanks;
|
||||
}
|
||||
}
|
||||
invalBlanks.nBlanks = nInvalBlanks;
|
||||
XP_MEMCPY( bqp, &invalBlanks, sizeof(*bqp) );
|
||||
} /* invalBlanksWithNeighbors */
|
||||
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
static HintAtts
|
||||
figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
||||
{
|
||||
HintAtts result = HINT_BORDER_NONE;
|
||||
|
||||
/* while lets us break to exit... */
|
||||
while ( board->trayVisState == TRAY_REVEALED && board->gi->allowHintRect ) {
|
||||
BdHintLimits limits;
|
||||
if ( dragDropGetHintLimits( board, &limits ) ) {
|
||||
/* do nothing */
|
||||
} else if ( board->hasHintRect[board->selPlayer] ) {
|
||||
limits = board->limits[board->selPlayer];
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
if ( col < limits.left ) break;
|
||||
if ( row < limits.top ) break;
|
||||
if ( col > limits.right ) break;
|
||||
if ( row > limits.bottom ) break;
|
||||
|
||||
if ( col == limits.left ) {
|
||||
result |= HINT_BORDER_LEFT;
|
||||
}
|
||||
if ( col == limits.right ) {
|
||||
result |= HINT_BORDER_RIGHT;
|
||||
}
|
||||
if ( row == limits.top) {
|
||||
result |= HINT_BORDER_TOP;
|
||||
}
|
||||
if ( row == limits.bottom ) {
|
||||
result |= HINT_BORDER_BOTTOM;
|
||||
}
|
||||
#ifndef XWFEATURE_SEARCHLIMIT_DOCENTERS
|
||||
if ( result == HINT_BORDER_NONE ) {
|
||||
result = HINT_BORDER_CENTER;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
} /* figureHintAtts */
|
||||
#endif
|
||||
|
||||
static XP_Bool
|
||||
rectContainsRect( XP_Rect* rect1, XP_Rect* rect2 )
|
||||
{
|
||||
return ( rect1->top <= rect2->top
|
||||
&& rect1->left <= rect2->left
|
||||
&& rect1->top + rect1->height >= rect2->top + rect2->height
|
||||
&& rect1->left + rect1->width >= rect2->left + rect2->width );
|
||||
} /* rectContainsRect */
|
||||
|
||||
static void
|
||||
makeMiniWindowForTrade( BoardCtxt* board )
|
||||
{
|
||||
const XP_UCHAR* text;
|
||||
|
||||
text = draw_getMiniWText( board->draw, INTRADE_MW_TEXT );
|
||||
|
||||
makeMiniWindowForText( board, text, MINIWINDOW_TRADING );
|
||||
} /* makeMiniWindowForTrade */
|
||||
|
||||
static void
|
||||
drawBoard( BoardCtxt* board )
|
||||
{
|
||||
if ( board->needsDrawing
|
||||
&& draw_boardBegin( board->draw,
|
||||
model_getDictionary( board->model ),
|
||||
&board->boardBounds,
|
||||
dfsFor( board, OBJ_BOARD ) ) ) {
|
||||
|
||||
XP_Bool allDrawn = XP_TRUE;
|
||||
XP_S16 lastCol, i;
|
||||
XP_S16 row;
|
||||
ModelCtxt* model = board->model;
|
||||
BlankQueue bq;
|
||||
XP_Rect arrowRect;
|
||||
|
||||
scrollIfCan( board ); /* this must happen before we count blanks
|
||||
since it invalidates squares */
|
||||
|
||||
/* This is freaking expensive!!!! PENDING FIXME Can't we start from
|
||||
what's invalid rather than scanning the entire model every time
|
||||
somebody dirties a single cell? */
|
||||
model_listPlacedBlanks( model, board->selPlayer,
|
||||
board->trayVisState == TRAY_REVEALED, &bq );
|
||||
invalBlanksWithNeighbors( board, &bq );
|
||||
|
||||
for ( row = board->yOffset; row <= board->lastVisibleRow; ++row ) {
|
||||
XP_U16 rowFlags = board->redrawFlags[row];
|
||||
if ( rowFlags != 0 ) {
|
||||
XP_U16 colMask;
|
||||
XP_U16 failedBits = 0;
|
||||
lastCol = model_numCols( model );
|
||||
for ( colMask = 1<<(lastCol-1); lastCol--; colMask >>= 1 ) {
|
||||
if ( (rowFlags & colMask) != 0 ) {
|
||||
if ( !drawCell( board, lastCol, row, XP_TRUE )) {
|
||||
failedBits |= colMask;
|
||||
allDrawn = XP_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
board->redrawFlags[row] = failedBits;
|
||||
}
|
||||
}
|
||||
|
||||
/* draw the blanks we skipped before */
|
||||
for ( i = 0; i < bq.nBlanks; ++i ) {
|
||||
if ( !drawCell( board, bq.col[i], bq.row[i], XP_FALSE ) ) {
|
||||
allDrawn = XP_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( board->trayVisState == TRAY_REVEALED ) {
|
||||
BoardArrow* arrow = &board->boardArrow[board->selPlayer];
|
||||
|
||||
if ( arrow->visible ) {
|
||||
XP_U16 col = arrow->col;
|
||||
XP_U16 row = arrow->row;
|
||||
if ( getCellRect( board, col, row, &arrowRect ) ) {
|
||||
XWBonusType bonus;
|
||||
HintAtts hintAtts;
|
||||
CellFlags flags = CELL_NONE;
|
||||
bonus = util_getSquareBonus( board->util, model,
|
||||
col, row );
|
||||
hintAtts = figureHintAtts( board, col, row );
|
||||
#ifdef KEYBOARD_NAV
|
||||
if ( cellFocused( board, col, row ) ) {
|
||||
flags |= CELL_ISCURSOR;
|
||||
}
|
||||
#endif
|
||||
draw_drawBoardArrow( board->draw, &arrowRect, bonus,
|
||||
arrow->vert, hintAtts, flags );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 ) );
|
||||
|
||||
board->needsDrawing = !allDrawn;
|
||||
}
|
||||
} /* drawBoard */
|
||||
|
||||
|
||||
static XP_Bool
|
||||
drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks )
|
||||
{
|
||||
XP_Bool success = XP_TRUE;
|
||||
XP_Rect cellRect;
|
||||
Tile tile;
|
||||
XP_Bool isBlank, isEmpty, recent, pending = XP_FALSE;
|
||||
XWBonusType bonus;
|
||||
ModelCtxt* model = board->model;
|
||||
DictionaryCtxt* dict = model_getDictionary( model );
|
||||
XP_U16 modelCol, modelRow;
|
||||
|
||||
if ( dict != NULL && getCellRect( board, col, row, &cellRect ) ) {
|
||||
|
||||
/* We want to invert EITHER the current pending tiles OR the most recent
|
||||
* move. So if the tray is visible AND there are tiles missing from it,
|
||||
* show them. Otherwise show the most recent move.
|
||||
*/
|
||||
XP_U16 selPlayer = board->selPlayer;
|
||||
XP_U16 curCount = model_getCurrentMoveCount( model, selPlayer );
|
||||
XP_Bool showPending = board->trayVisState == TRAY_REVEALED
|
||||
&& curCount > 0;
|
||||
|
||||
flipIf( board, col, row, &modelCol, &modelRow );
|
||||
|
||||
/* This 'while' is only here so I can 'break' below */
|
||||
while ( board->trayVisState == TRAY_HIDDEN ||
|
||||
!rectContainsRect( &board->trayBounds, &cellRect ) ) {
|
||||
XP_UCHAR ch[4] = {'\0'};
|
||||
XP_S16 owner = -1;
|
||||
XP_Bool invert = XP_FALSE;
|
||||
XP_Bitmap bitmap = NULL;
|
||||
XP_UCHAR* textP = NULL;
|
||||
HintAtts hintAtts;
|
||||
CellFlags flags = CELL_NONE;
|
||||
XP_Bool isOrigin;
|
||||
|
||||
isEmpty = !model_getTile( model, modelCol, modelRow, showPending,
|
||||
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;
|
||||
flags |= CELL_ISEMPTY;
|
||||
} else if ( isBlank && skipBlanks ) {
|
||||
break;
|
||||
} else {
|
||||
if ( board->showColors ) {
|
||||
owner = (XP_S16)model_getCellOwner( model, modelCol,
|
||||
modelRow );
|
||||
}
|
||||
|
||||
invert = showPending? pending : recent;
|
||||
|
||||
if ( board->showCellValues ) {
|
||||
Tile valTile = isBlank? dict_getBlankTile( dict ) : tile;
|
||||
XP_U16 val = dict_getTileValue( dict, valTile );
|
||||
XP_SNPRINTF( ch, sizeof(ch), (XP_UCHAR*)"%d", val );
|
||||
textP = ch;
|
||||
} else if ( dict_faceIsBitmap( dict, tile ) ) {
|
||||
bitmap = dict_getFaceBitmap( dict, tile, XP_FALSE );
|
||||
XP_ASSERT( !!bitmap );
|
||||
} else {
|
||||
(void)dict_tilesToString( dict, &tile, 1, ch, sizeof(ch) );
|
||||
textP = ch;
|
||||
}
|
||||
}
|
||||
bonus = util_getSquareBonus( board->util, model, col, row );
|
||||
hintAtts = figureHintAtts( board, col, row );
|
||||
|
||||
if ( (col==board->star_row) && (row==board->star_row) ) {
|
||||
flags |= CELL_ISSTAR;
|
||||
}
|
||||
if ( invert ) {
|
||||
flags |= CELL_HIGHLIGHT;
|
||||
}
|
||||
if ( isBlank ) {
|
||||
flags |= CELL_ISBLANK;
|
||||
}
|
||||
#ifdef KEYBOARD_NAV
|
||||
if ( cellFocused( board, col, row ) ) {
|
||||
flags |= CELL_ISCURSOR;
|
||||
}
|
||||
#endif
|
||||
|
||||
success = draw_drawCell( board->draw, &cellRect, textP, bitmap,
|
||||
tile, owner, bonus, hintAtts, flags );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
} /* drawCell */
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
DrawFocusState
|
||||
dfsFor( BoardCtxt* board, BoardObjectType obj )
|
||||
{
|
||||
DrawFocusState dfs;
|
||||
if ( board->focussed == obj ) {
|
||||
if ( board->focusHasDived ) {
|
||||
dfs = DFS_DIVED;
|
||||
} else {
|
||||
dfs = DFS_TOP;
|
||||
}
|
||||
} else {
|
||||
dfs = DFS_NONE;
|
||||
}
|
||||
return dfs;
|
||||
} /* dfsFor */
|
||||
|
||||
static XP_Bool
|
||||
cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row )
|
||||
{
|
||||
XP_Bool focussed = XP_FALSE;
|
||||
|
||||
if ( board->focussed == OBJ_BOARD ) {
|
||||
if ( board->focusHasDived ) {
|
||||
if ( (col == board->bdCursor[board->selPlayer].col)
|
||||
&& (row == board->bdCursor[board->selPlayer].row) ) {
|
||||
focussed = XP_TRUE;
|
||||
}
|
||||
} else {
|
||||
#ifdef PERIMETER_FOCUS
|
||||
focussed = (col == 0)
|
||||
|| (col == model_numCols(board->model) - 1)
|
||||
|| (row == board->yOffset)
|
||||
|| (row == board->lastVisibleRow);
|
||||
#else
|
||||
focussed = XP_TRUE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return focussed;
|
||||
} /* cellFocused */
|
||||
#endif
|
||||
|
||||
#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,
|
||||
board->selPlayer, flags );
|
||||
}
|
||||
}
|
||||
} /* drawDragTileIf */
|
||||
#endif
|
||||
|
||||
static void
|
||||
scrollIfCan( BoardCtxt* board )
|
||||
{
|
||||
if ( board->yOffset != board->prevYScrollOffset ) {
|
||||
XP_Rect scrollR = board->boardBounds;
|
||||
XP_Bool scrolled;
|
||||
XP_S16 dist;
|
||||
|
||||
#ifdef PERIMETER_FOCUS
|
||||
if ( (board->focussed == OBJ_BOARD) && !board->focusHasDived ) {
|
||||
invalOldPerimeter( board );
|
||||
}
|
||||
#endif
|
||||
invalSelTradeWindow( board );
|
||||
dist = (board->yOffset - board->prevYScrollOffset)
|
||||
* board->boardVScale;
|
||||
|
||||
scrolled = draw_vertScrollBoard( board->draw, &scrollR, dist,
|
||||
dfsFor( board, OBJ_BOARD ) );
|
||||
|
||||
if ( scrolled ) {
|
||||
/* inval the rows that have been scrolled into view. I'm cheating
|
||||
making the client figure the inval rect, but Palm's the first
|
||||
client and it does it so well.... */
|
||||
invalCellsUnderRect( board, &scrollR );
|
||||
} else {
|
||||
board_invalAll( board );
|
||||
}
|
||||
board->prevYScrollOffset = board->yOffset;
|
||||
}
|
||||
} /* scrollIfCan */
|
||||
|
||||
static void
|
||||
drawTradeWindowIf( BoardCtxt* board )
|
||||
{
|
||||
if ( board->tradingMiniWindowInvalid &&
|
||||
TRADE_IN_PROGRESS(board) && board->trayVisState == TRAY_REVEALED ) {
|
||||
MiniWindowStuff* stuff;
|
||||
|
||||
makeMiniWindowForTrade( board );
|
||||
|
||||
stuff = &board->miniWindowStuff[MINIWINDOW_TRADING];
|
||||
draw_drawMiniWindow( board->draw, stuff->text,
|
||||
&stuff->rect, (void**)NULL );
|
||||
|
||||
board->tradingMiniWindowInvalid = XP_FALSE;
|
||||
}
|
||||
} /* drawTradeWindowIf */
|
||||
|
||||
XP_Bool
|
||||
board_draw( BoardCtxt* board )
|
||||
{
|
||||
if ( board->boardBounds.width > 0 ) {
|
||||
|
||||
drawScoreBoard( board );
|
||||
|
||||
drawTray( board );
|
||||
|
||||
drawBoard( board );
|
||||
}
|
||||
return !board->needsDrawing;
|
||||
} /* board_draw */
|
||||
|
||||
#ifdef CPLUS
|
||||
}
|
||||
#endif
|
|
@ -151,6 +151,7 @@ struct BoardCtxt {
|
|||
XP_Bool focusHasDived;
|
||||
#endif
|
||||
XP_U8 dividerLoc[MAX_NUM_PLAYERS]; /* 0 means left of 0th tile, etc. */
|
||||
XP_Bool dividerSelected[MAX_NUM_PLAYERS]; /* probably need to save this */
|
||||
|
||||
XP_U16 scoreDims[MAX_NUM_PLAYERS];
|
||||
|
||||
|
@ -176,7 +177,7 @@ struct BoardCtxt {
|
|||
TileBit trayInvalBits;
|
||||
TileBit traySelBits[MAX_NUM_PLAYERS];
|
||||
#ifdef KEYBOARD_NAV
|
||||
XP_U8 trayCursorLoc[MAX_NUM_PLAYERS];
|
||||
XP_U8 trayCursorLoc[MAX_NUM_PLAYERS]; /* includes divider!!! */
|
||||
XP_U8 scoreCursorLoc;
|
||||
#endif
|
||||
|
||||
|
@ -226,10 +227,20 @@ XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
|||
void invalTilesUnderRect( BoardCtxt* board, const XP_Rect* rect );
|
||||
void invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
|
||||
XP_U16 rowB );
|
||||
void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
void invalDragObj( BoardCtxt* board, const DragObjInfo* di );
|
||||
void invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex );
|
||||
void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
|
||||
XP_U16 tileIndex2 );
|
||||
void makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
|
||||
MiniWindowType winType );
|
||||
XP_Bool getCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
XP_Rect* rect);
|
||||
void getDragCellRect( BoardCtxt* board, XP_U16 col, XP_U16 row,
|
||||
XP_Rect* rectP );
|
||||
void invalSelTradeWindow( BoardCtxt* board );
|
||||
void invalCellsUnderRect( BoardCtxt* board, const XP_Rect* rect );
|
||||
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
void invalCurHintRect( BoardCtxt* board, XP_U16 player );
|
||||
#endif
|
||||
|
@ -249,12 +260,16 @@ XP_Bool checkScrollCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
|||
XP_Bool onBorderCanScroll( const BoardCtxt* board, XP_U16 row, XP_S16* change );
|
||||
XP_Bool adjustYOffset( BoardCtxt* board, XP_S16 moveBy );
|
||||
|
||||
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,
|
||||
XP_Bool preflightOnly, XP_Bool* up );
|
||||
XP_Bool tray_keyAction( BoardCtxt* board );
|
||||
DrawFocusState dfsFor( BoardCtxt* board, BoardObjectType obj );
|
||||
void shiftFocusUp( BoardCtxt* board, XP_Key key );
|
||||
void getFocussedTileCenter( BoardCtxt* board, XP_U16* xp, XP_U16* yp );
|
||||
void getRectCenter( const XP_Rect* rect, XP_U16* xp, XP_U16* yp );
|
||||
#else
|
||||
# define dfsFor( board, obj ) DFS_NONE
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,7 @@ COMMONOBJDIR = ../common/$(PLATFORM)
|
|||
|
||||
COMMONSRC = \
|
||||
$(COMMONDIR)/board.c \
|
||||
$(COMMONDIR)/boarddrw.c \
|
||||
$(COMMONDIR)/dragdrpp.c \
|
||||
$(COMMONDIR)/scorebdp.c \
|
||||
$(COMMONDIR)/tray.c \
|
||||
|
@ -48,7 +49,7 @@ COMMONSRC = \
|
|||
|
||||
COMMON1 = \
|
||||
$(COMMONOBJDIR)/board.o \
|
||||
$(COMMONOBJDIR)/dragdrpp.o \
|
||||
$(COMMONOBJDIR)/boarddrw.o \
|
||||
$(COMMONOBJDIR)/tray.o \
|
||||
$(COMMONOBJDIR)/scorebdp.o \
|
||||
$(COMMONOBJDIR)/draw.o \
|
||||
|
@ -66,6 +67,7 @@ COMMON3 = \
|
|||
$(COMMONOBJDIR)/engine.o \
|
||||
|
||||
COMMON4 = \
|
||||
$(COMMONOBJDIR)/dragdrpp.o \
|
||||
$(COMMONOBJDIR)/memstream.o \
|
||||
$(COMMONOBJDIR)/comms.o \
|
||||
$(COMMONOBJDIR)/mempool.o \
|
||||
|
|
Loading…
Reference in a new issue