mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-29 10:26:36 +01:00
210c59ef9b
to query model for values. Now everybody else queries new model API rather than client via util_getSquareBonus(), model uses its internal values if present otherwise falls back to util_getSquareBonus(), and internalizes the array as part of the game. Now it should be easier to have different bonus patterns and to have them exchanged as part of network game init.
635 lines
21 KiB
C
635 lines
21 KiB
C
/* -*- compile-command: "cd ../linux && make MEMDEBUG=TRUE -j3"; -*- */
|
|
/*
|
|
* Copyright 1997 - 2011 by Eric House (xwords@eehouse.org). All rights
|
|
* reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/* 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 );
|
|
#ifdef KEYBOARD_NAV
|
|
static XP_Bool cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row );
|
|
#endif
|
|
#ifdef XWFEATURE_MINIWIN
|
|
static void drawTradeWindowIf( BoardCtxt* board );
|
|
#else
|
|
# define drawTradeWindowIf( board )
|
|
#endif
|
|
|
|
|
|
#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.) */
|
|
ScrollData* vsd = &board->sd[SCROLL_V];
|
|
XP_S16 diff = vsd->offset - board->prevYScrollOffset;
|
|
XP_U16 firstRow, lastRow;
|
|
XP_ASSERT( diff != 0 );
|
|
if ( diff < 0 ) {
|
|
/* moving up; inval row previously on bottom */
|
|
firstRow = vsd->offset + 1;
|
|
lastRow = board->prevYScrollOffset;
|
|
} else {
|
|
XP_U16 nVisible = vsd->lastVisible - vsd->offset + 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->hintsNotAllowed
|
|
&& board->gi->allowHintRect ) {
|
|
BdHintLimits limits;
|
|
if ( dragDropGetHintLimits( board, &limits ) ) {
|
|
/* do nothing */
|
|
} else if ( board->selInfo->hasHintRect ) {
|
|
limits = board->selInfo->limits;
|
|
} 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 */
|
|
|
|
#ifdef XWFEATURE_MINIWIN
|
|
static void
|
|
makeMiniWindowForTrade( BoardCtxt* board )
|
|
{
|
|
const XP_UCHAR* text;
|
|
|
|
text = draw_getMiniWText( board->draw, INTRADE_MW_TEXT );
|
|
|
|
makeMiniWindowForText( board, text, MINIWINDOW_TRADING );
|
|
} /* makeMiniWindowForTrade */
|
|
#endif
|
|
|
|
#ifdef XWFEATURE_CROSSHAIRS
|
|
static CellFlags
|
|
flagsForCrosshairs( const BoardCtxt* board, XP_U16 col, XP_U16 row )
|
|
{
|
|
CellFlags flags = 0;
|
|
XP_Bool inHor, inVert;
|
|
dragDropInCrosshairs( board, col, row, &inHor, &inVert );
|
|
if ( inHor ) {
|
|
flags |= CELL_CROSSHOR;
|
|
}
|
|
if ( inVert ) {
|
|
flags |= CELL_CROSSVERT;
|
|
}
|
|
return flags;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
drawBoard( BoardCtxt* board )
|
|
{
|
|
if ( board->needsDrawing
|
|
&& draw_boardBegin( board->draw, &board->boardBounds,
|
|
board->sd[SCROLL_H].scale,
|
|
board->sd[SCROLL_V].scale,
|
|
dfsFor( board, OBJ_BOARD ) ) ) {
|
|
|
|
XP_Bool allDrawn = XP_TRUE;
|
|
XP_S16 i;
|
|
XP_S16 col, row, nVisCols;
|
|
ModelCtxt* model = board->model;
|
|
BoardArrow const* arrow = NULL;
|
|
ScrollData* hsd = &board->sd[SCROLL_H];
|
|
ScrollData* vsd = &board->sd[SCROLL_V];
|
|
BlankQueue bq;
|
|
|
|
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 );
|
|
dragDropAppendBlank( board, &bq );
|
|
invalBlanksWithNeighbors( board, &bq );
|
|
|
|
/* figure out now, before clearing inval bits, if we'll need to draw
|
|
the arrow later */
|
|
if ( board->trayVisState == TRAY_REVEALED ) {
|
|
BoardArrow const* tmpArrow = &board->selInfo->boardArrow;
|
|
if ( tmpArrow->visible ) {
|
|
XP_U16 col = tmpArrow->col;
|
|
XP_U16 row = tmpArrow->row;
|
|
if ( INVAL_BIT_SET( board, col, row )
|
|
&& !cellOccupied( board, col, row, XP_TRUE ) ) {
|
|
arrow = tmpArrow;
|
|
}
|
|
}
|
|
}
|
|
|
|
nVisCols = model_numCols( model ) - board->zoomCount;
|
|
for ( row = vsd->offset; row <= vsd->lastVisible; ++row ) {
|
|
RowFlags rowFlags = board->redrawFlags[row];
|
|
if ( rowFlags != 0 ) {
|
|
RowFlags failedBits = 0;
|
|
for ( col = 0; col < nVisCols; ++col ) {
|
|
RowFlags colMask = 1 << (col + hsd->offset);
|
|
if ( 0 != (rowFlags & colMask) ) {
|
|
if ( !drawCell( board, col + hsd->offset,
|
|
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 ( !!arrow ) {
|
|
XP_U16 col = arrow->col;
|
|
XP_U16 row = arrow->row;
|
|
XP_Rect arrowRect;
|
|
if ( getCellRect( board, col, row, &arrowRect ) ) {
|
|
XWBonusType bonus;
|
|
HintAtts hintAtts;
|
|
CellFlags flags = CELL_NONE;
|
|
bonus = model_getSquareBonus( model, col, row );
|
|
hintAtts = figureHintAtts( board, col, row );
|
|
#ifdef KEYBOARD_NAV
|
|
if ( cellFocused( board, col, row ) ) {
|
|
flags |= CELL_ISCURSOR;
|
|
}
|
|
#endif
|
|
#ifdef XWFEATURE_CROSSHAIRS
|
|
flags |= flagsForCrosshairs( board, col, row );
|
|
#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_Bitmaps bitmaps;
|
|
XP_Bitmaps* bptr = NULL;
|
|
const 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 );
|
|
isEmpty = XP_FALSE;
|
|
}
|
|
showPending = pending = XP_TRUE;
|
|
}
|
|
|
|
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, VSIZE(ch), "%d", val );
|
|
textP = ch;
|
|
} else {
|
|
if ( dict_faceIsBitmap( dict, tile ) ) {
|
|
dict_getFaceBitmaps( dict, tile, &bitmaps );
|
|
bptr = &bitmaps;
|
|
}
|
|
textP = dict_getTileString( dict, tile );
|
|
}
|
|
}
|
|
bonus = model_getSquareBonus( 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
|
|
#ifdef XWFEATURE_CROSSHAIRS
|
|
flags |= flagsForCrosshairs( board, col, row );
|
|
#endif
|
|
|
|
success = draw_drawCell( board->draw, &cellRect, textP, bptr,
|
|
tile, owner, bonus, hintAtts, flags );
|
|
break;
|
|
}
|
|
}
|
|
return success;
|
|
} /* drawCell */
|
|
|
|
#ifdef KEYBOARD_NAV
|
|
DrawFocusState
|
|
dfsFor( BoardCtxt* board, BoardObjectType obj )
|
|
{
|
|
DrawFocusState dfs;
|
|
if ( (board->focussed == obj) && !board->hideFocus ) {
|
|
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;
|
|
const ScrollData* hsd = &board->sd[SCROLL_H];
|
|
const ScrollData* vsd = &board->sd[SCROLL_V];
|
|
if ( (board->focussed == OBJ_BOARD) && !board->hideFocus ) {
|
|
if ( board->focusHasDived ) {
|
|
if ( (col == board->selInfo->bdCursor.col)
|
|
&& (row == board->selInfo->bdCursor.row) ) {
|
|
focussed = XP_TRUE;
|
|
}
|
|
} else {
|
|
#ifdef PERIMETER_FOCUS
|
|
focussed = (col == hsd->offset)
|
|
|| (col == hsd->lastVisible)
|
|
|| (row == vsd->offset)
|
|
|| (row == vsd->lastVisible);
|
|
#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;
|
|
const XP_UCHAR* face;
|
|
XP_Bitmaps bitmaps;
|
|
XP_S16 value;
|
|
CellFlags flags;
|
|
|
|
getDragCellRect( board, col, row, &rect );
|
|
|
|
dragDropTileInfo( board, &tile, &isBlank );
|
|
|
|
face = getTileDrawInfo( board, tile, isBlank, &bitmaps,
|
|
&value );
|
|
|
|
flags = CELL_DRAGCUR;
|
|
if ( isBlank ) {
|
|
flags |= CELL_ISBLANK;
|
|
}
|
|
if ( board->hideValsInTray && !board->showCellValues ) {
|
|
flags |= CELL_VALHIDDEN;
|
|
}
|
|
draw_drawTileMidDrag( board->draw, &rect, face,
|
|
bitmaps.nBitmaps > 0 ? &bitmaps : NULL,
|
|
value, board->selPlayer, flags );
|
|
}
|
|
}
|
|
} /* drawDragTileIf */
|
|
#endif
|
|
|
|
static XP_S16
|
|
sumRowHeights( const BoardCtxt* board, XP_U16 row1, XP_U16 row2 )
|
|
{
|
|
const ScrollData* vsd = &board->sd[SCROLL_V];
|
|
XP_S16 sign = row1 > row2 ? -1 : 1;
|
|
XP_S16 result, ii;
|
|
if ( sign < 0 ) {
|
|
XP_U16 tmp = row1;
|
|
row1 = row2;
|
|
row2 = tmp;
|
|
}
|
|
for ( result = 0, ii = row1; ii < row2; ++ii ) {
|
|
result += vsd->dims[ii];
|
|
}
|
|
return result * sign;
|
|
}
|
|
|
|
static void
|
|
scrollIfCan( BoardCtxt* board )
|
|
{
|
|
ScrollData* vsd = &board->sd[SCROLL_V];
|
|
if ( vsd->offset != board->prevYScrollOffset ) {
|
|
XP_Rect scrollR = board->boardBounds;
|
|
XP_Bool scrolled;
|
|
XP_S16 dist;
|
|
|
|
#if defined KEYBOARD_NAV && defined PERIMETER_FOCUS
|
|
if ( (board->focussed == OBJ_BOARD)
|
|
&& !board->focusHasDived
|
|
&& !board->hideFocus ) {
|
|
invalOldPerimeter( board );
|
|
}
|
|
#endif
|
|
invalSelTradeWindow( board );
|
|
|
|
dist = sumRowHeights( board, board->prevYScrollOffset, vsd->offset );
|
|
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 = vsd->offset;
|
|
}
|
|
} /* scrollIfCan */
|
|
|
|
#ifdef XWFEATURE_MINIWIN
|
|
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 */
|
|
#endif
|
|
|
|
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
|