create alternate scoreboard draw flow, disabled by compile-time flag,

that does layout and draw in a single pass and with more information
so platform has more responsibilty for dealing with space constraints
and can, I hope, do a better job.  There's no change until the flag is
turned on.  Works for GTK with flag on, but is stubbed out for ncurses.
This commit is contained in:
Eric House 2012-06-26 07:20:09 -07:00
parent d8e4b6481c
commit 2fc2a60842
5 changed files with 293 additions and 100 deletions

View file

@ -131,17 +131,26 @@ typedef struct DrawCtxVTable {
XP_Bool DRAW_VTABLE_NAME(trayBegin) ( DrawCtx* dctx, const XP_Rect* rect,
XP_U16 owner, XP_S16 score,
DrawFocusState dfs );
void DRAW_VTABLE_NAME(measureRemText) ( DrawCtx* dctx, const XP_Rect* r,
XP_S16 nTilesLeft,
XP_U16* width, XP_U16* height );
void DRAW_VTABLE_NAME(drawRemText) (DrawCtx* dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_S16 nTilesLeft, XP_Bool focussed );
XP_Bool DRAW_VTABLE_NAME(scoreBegin) ( DrawCtx* dctx, const XP_Rect* rect,
XP_U16 numPlayers,
const XP_S16* const scores,
XP_S16 remCount, DrawFocusState dfs );
#ifdef XWFEATURE_SCOREONEPASS
void DRAW_VTABLE_NAME(drawRemText) ( DrawCtx* dctx, XP_S16 nTilesLeft,
XP_Bool focussed, XP_Rect* rect );
void DRAW_VTABLE_NAME(score_drawPlayers)( DrawCtx* dctx,
const XP_Rect* scoreRect,
XP_U16 nPlayers,
DrawScoreInfo playerData[],
XP_Rect playerRects[] );
#else
void DRAW_VTABLE_NAME(measureRemText) ( DrawCtx* dctx, const XP_Rect* r,
XP_S16 nTilesLeft,
XP_U16* width, XP_U16* height );
void DRAW_VTABLE_NAME(drawRemText) ( DrawCtx* dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_S16 nTilesLeft, XP_Bool focussed );
void DRAW_VTABLE_NAME(measureScoreText) ( DrawCtx* dctx,
const XP_Rect* r,
const DrawScoreInfo* dsi,
@ -151,7 +160,7 @@ typedef struct DrawCtxVTable {
const XP_Rect* rOuter,
XP_U16 gotPct,
const DrawScoreInfo* dsi );
#endif
void DRAW_VTABLE_NAME(score_pendingScore) ( DrawCtx* dctx,
const XP_Rect* rect,
XP_S16 score,
@ -271,14 +280,21 @@ struct DrawCtx {
CALL_DRAW_NAME3(vertScrollBoard, (dc),(r),(d),(f))
#define draw_scoreBegin( dc, r, t, s, c, f ) \
CALL_DRAW_NAME5( scoreBegin,(dc), (r), (t), (s), (c), (f))
#define draw_measureRemText( dc, r, n, wp, hp ) \
#ifdef XWFEATURE_SCOREONEPASS
# define draw_drawRemText( dc, nt, f, ro ) \
CALL_DRAW_NAME3(drawRemText, (dc), (nt), (f), (ro) )
# define draw_score_drawPlayers( dc, r, np, pd, pr ) \
CALL_DRAW_NAME4(score_drawPlayers, (dc), (r), (np), (pd), (pr) )
#else
# define draw_measureRemText( dc, r, n, wp, hp ) \
CALL_DRAW_NAME4(measureRemText, (dc), (r), (n), (wp), (hp) )
#define draw_drawRemText( dc, ri, ro, n, f ) \
# define draw_drawRemText( dc, ri, ro, n, f ) \
CALL_DRAW_NAME4(drawRemText, (dc), (ri), (ro), (n), (f) )
#define draw_measureScoreText(dc,r,dsi,wp,hp) \
# define draw_measureScoreText(dc,r,dsi,wp,hp) \
CALL_DRAW_NAME4(measureScoreText,(dc),(r),(dsi),(wp),(hp))
#define draw_score_drawPlayer(dc, ri, ro, gp, dsi) \
# define draw_score_drawPlayer(dc, ri, ro, gp, dsi) \
CALL_DRAW_NAME4(score_drawPlayer,(dc),(ri),(ro),(gp),(dsi))
#endif
#define draw_score_pendingScore(dc, r, s, p, f ) \
CALL_DRAW_NAME4(score_pendingScore,(dc), (r), (s), (p), (f))
#define draw_drawTimer( dc, r, plyr, sec ) \

View file

@ -37,6 +37,113 @@ board_ScoreCallback( void* closure, XP_S16 player, XP_UCHAR* expl,
expl, explLen );
} /* board_ScoreCallback */
#ifdef XWFEATURE_SCOREONEPASS
void
drawScoreBoard( BoardCtxt* board )
{
if ( board->scoreBoardInvalid ) {
XP_U16 ii;
XP_U16 nPlayers = board->gi->nPlayers;
DrawFocusState dfs = dfsFor( board, OBJ_SCORE );
ScoresArray scores;
ModelCtxt* model = board->model;
XP_S16 nTilesInPool = server_countTilesInPool( board->server );
if ( board->gameOver ) {
model_figureFinalScores( model, &scores, NULL );
} else {
for ( ii = 0; ii < nPlayers; ++ii ) {
scores.arr[ii] = model_getPlayerScore( model, ii );
}
}
if ( draw_scoreBegin( board->draw, &board->scoreBdBounds, nPlayers,
scores.arr, nTilesInPool, dfs ) ) {
XP_S16 curTurn = server_getCurrentTurn( board->server );
XP_U16 selPlayer = board->selPlayer;
XP_Rect scoreRect;
XP_Rect playerRects[nPlayers];
XP_U16 remDim;
XP_Bool isVertical = !board->scoreSplitHor;
XP_Bool remFocussed = XP_FALSE;
XP_Bool focusAll = XP_FALSE;
DrawScoreInfo data[nPlayers];
#ifdef KEYBOARD_NAV
XP_S16 cursorIndex = -1;
if ( (board->focussed == OBJ_SCORE) && !board->hideFocus ) {
focusAll = !board->focusHasDived;
if ( !focusAll ) {
cursorIndex = board->scoreCursorLoc;
remFocussed = CURSOR_LOC_REM == cursorIndex;
--cursorIndex;
}
}
#endif
XP_MEMSET( playerRects, 0, sizeof(playerRects) );
XP_MEMSET( data, 0, sizeof(data) );
scoreRect = board->scoreBdBounds;
draw_drawRemText( board->draw, nTilesInPool, focusAll || remFocussed,
&scoreRect );
XP_ASSERT( rectContainsRect( &board->scoreBdBounds, &scoreRect ) );
remDim = isVertical? scoreRect.height : scoreRect.width;
board->remDim = remDim;
#ifdef KEYBOARD_NAV
board->remRect = scoreRect;
if ( 0 == remDim && board->scoreCursorLoc == CURSOR_LOC_REM ) {
board->scoreCursorLoc = selPlayer + 1;
}
#endif
scoreRect = board->scoreBdBounds;
if ( isVertical ) {
scoreRect.height -= remDim;
scoreRect.top += remDim;
} else {
scoreRect.width -= remDim;
scoreRect.left += remDim;
}
for ( ii = 0; ii < nPlayers; ++ii ) {
DrawScoreInfo* dsi = &data[ii];
LocalPlayer* lp = &board->gi->players[ii];
dsi->lsc = board_ScoreCallback;
dsi->lscClosure = model;
#ifdef KEYBOARD_NAV
if ( (ii == cursorIndex) || focusAll ) {
dsi->flags |= CELL_ISCURSOR;
}
#endif
dsi->playerNum = ii;
dsi->totalScore = scores.arr[ii];
dsi->isTurn = (ii == curTurn);
dsi->name = emptyStringIfNull(lp->name);
dsi->selected = board->trayVisState != TRAY_HIDDEN
&& ii==selPlayer;
dsi->isRobot = LP_IS_ROBOT(lp);
dsi->isRemote = !lp->isLocal;
dsi->nTilesLeft = (nTilesInPool > 0)? -1:
model_getNumTilesTotal( model, ii );
}
draw_score_drawPlayers( board->draw, &scoreRect, nPlayers, data, playerRects );
for ( ii = 0; ii < nPlayers; ++ii ) {
XP_MEMCPY( &board->pti[ii].scoreRects, &playerRects[ii],
sizeof(board->pti[ii].scoreRects) );
}
draw_objFinished( board->draw, OBJ_SCORE,
&board->scoreBdBounds, dfs );
board->scoreBoardInvalid = XP_FALSE;
}
}
drawTimer( board );
} /* drawScoreBoard */
#else
static void
centerIn( XP_Rect* rInner, const XP_Rect* rOuter, XP_U16 width, XP_U16 height )
{
@ -78,10 +185,7 @@ drawScoreBoard( BoardCtxt* board )
XP_Bool remFocussed = XP_FALSE;
XP_Bool focusAll = XP_FALSE;
#ifdef KEYBOARD_NAV
XP_Rect cursorRect;
XP_Rect* cursorRectP = NULL;
XP_S16 cursorIndex = -1;
if ( (board->focussed == OBJ_SCORE) && !board->hideFocus ) {
focusAll = !board->focusHasDived;
if ( !focusAll ) {
@ -209,10 +313,6 @@ drawScoreBoard( BoardCtxt* board )
#ifdef KEYBOARD_NAV
XP_MEMCPY( &board->pti[ii].scoreRects, &scoreRect,
sizeof(scoreRect) );
if ( ii == cursorIndex ) {
cursorRect = scoreRect;
cursorRectP = &cursorRect;
}
#endif
*adjustPt += *adjustDim;
}
@ -228,6 +328,7 @@ drawScoreBoard( BoardCtxt* board )
drawTimer( board );
} /* drawScoreBoard */
#endif
static XP_S16
figureSecondsLeft( BoardCtxt* board )

View file

@ -95,6 +95,7 @@ DEFINES += -DXWFEATURE_WALKDICT
DEFINES += -DXWFEATURE_WALKDICT_FILTER
DEFINES += -DXWFEATURE_DICTSANITY
DEFINES += -DHASH_STREAM
#DEFINES += -DXWFEATURE_SCOREONEPASS
# MAX_ROWS controls STREAM_VERS_BIGBOARD and with it move hashing
DEFINES += -DMAX_ROWS=32

View file

@ -109,6 +109,17 @@ curses_draw_scoreBegin( DrawCtx* p_dctx, const XP_Rect* rect,
return XP_TRUE;
} /* curses_draw_scoreBegin */
#ifdef XWFEATURE_SCOREONEPASS
static void
curses_draw_drawRemText( DrawCtx* p_dctx, XP_S16 nTilesLeft,
XP_Bool focussed, XP_Rect* rect )
{
XP_USE(p_dctx);
XP_USE(nTilesLeft);
XP_USE(focussed);
XP_USE(rect);
}
#else
static void
formatRemText( char* buf, int bufLen, XP_S16 nTilesLeft, int width )
{
@ -145,7 +156,10 @@ curses_draw_drawRemText( DrawCtx* p_dctx, const XP_Rect* rInner,
cursesHiliteRect( dctx->boardWin, rInner );
}
} /* curses_draw_drawRemText */
#endif
#ifdef XWFEATURE_SCOREONEPASS
#else
static int
fitIn( char* buf, int len, int* rem, const char* str )
{
@ -243,6 +257,27 @@ curses_draw_measureScoreText( DrawCtx* XP_UNUSED(p_dctx),
*height = 1; /* one line per player */
} /* curses_draw_measureScoreText */
static void
curses_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_U16 XP_UNUSED(gotPct), const DrawScoreInfo* dsi )
{
CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx;
char buf[100];
int y = rInner->top;
curses_draw_clearRect( p_dctx, rOuter );
/* print the name and turn/remoteness indicator */
formatScoreText( buf, sizeof(buf), dsi, rInner->width );
mvwprintw( dctx->boardWin, y, rOuter->left, buf );
if ( (dsi->flags&CELL_ISCURSOR) != 0 ) {
cursesHiliteRect( dctx->boardWin, rOuter );
}
} /* curses_draw_score_drawPlayer */
#endif
static void
curses_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect,
XP_S16 score, XP_U16 XP_UNUSED(playerNum),
@ -275,26 +310,6 @@ curses_draw_objFinished( DrawCtx* p_dctx, BoardObjectType XP_UNUSED(typ),
#define MY_PAIR 1
static void
curses_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_U16 XP_UNUSED(gotPct), const DrawScoreInfo* dsi )
{
CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx;
char buf[100];
int y = rInner->top;
curses_draw_clearRect( p_dctx, rOuter );
/* print the name and turn/remoteness indicator */
formatScoreText( buf, sizeof(buf), dsi, rInner->width );
mvwprintw( dctx->boardWin, y, rOuter->left, buf );
if ( (dsi->flags&CELL_ISCURSOR) != 0 ) {
cursesHiliteRect( dctx->boardWin, rOuter );
}
} /* curses_draw_score_drawPlayer */
static XP_Bool
curses_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect,
const XP_UCHAR* letter,
@ -557,11 +572,15 @@ cursesDrawCtxtMake( WINDOW* boardWin )
SET_VTABLE_ENTRY( dctx->vtable, draw_trayBegin, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_scoreBegin, curses );
#ifdef XWFEATURE_SCOREONEPASS
SET_VTABLE_ENTRY( dctx->vtable, draw_drawRemText, curses );
#else
SET_VTABLE_ENTRY( dctx->vtable, draw_measureRemText, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawRemText, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_measureScoreText, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_score_pendingScore, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_score_drawPlayer, curses );
#endif
SET_VTABLE_ENTRY( dctx->vtable, draw_score_pendingScore, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawCell, curses );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawTile, curses );

View file

@ -44,6 +44,10 @@ typedef struct FontPerSize {
PangoLayout* layout;
} FontPerSize;
static void gtk_draw_measureScoreText( DrawCtx* p_dctx, const XP_Rect* bounds,
const DrawScoreInfo* dsi,
XP_U16* widthP, XP_U16* heightP );
/* static GdkGC* newGCForColor( GdkWindow* window, XP_Color* newC ); */
static void
gtkInsetRect( XP_Rect* r, short i )
@ -899,6 +903,113 @@ gtkDrawDrawRemText( DrawCtx* p_dctx, const XP_Rect* rect, XP_S16 nTilesLeft,
}
} /* gtkDrawDrawRemText */
static void
gtk_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_U16 XP_UNUSED(gotPct), const DrawScoreInfo* dsi )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Bool hasCursor = (dsi->flags & CELL_ISCURSOR) != 0;
GdkColor* cursor = NULL;
XP_U16 playerNum = dsi->playerNum;
const XP_UCHAR* scoreBuf = dctx->scoreCache[playerNum].str;
XP_U16 fontHt = dctx->scoreCache[playerNum].fontHt;
if ( hasCursor ) {
cursor = &dctx->cursor;
gtkFillRect( dctx, rOuter, cursor );
}
#ifdef USE_CAIRO
//gdk_cairo_set_source_color( dctx->cr, &dctx->playerColors[playerNum] );
#else
gdk_gc_set_foreground( dctx->drawGC, &dctx->playerColors[playerNum] );
#endif
if ( dsi->selected ) {
XP_Rect selRect = *rOuter;
XP_S16 diff;
if ( dctx->scoreIsVertical ) {
diff = selRect.height - rInner->height;
} else {
diff = selRect.width - rInner->width;
}
if ( diff > 0 ) {
if ( dctx->scoreIsVertical ) {
selRect.height -= diff>>1;
selRect.top += diff>>2;
} else {
selRect.width -= diff>>1;
selRect.left += diff>>2;
}
}
draw_rectangle( dctx, DRAW_WHAT(dctx), dctx->drawGC,
TRUE, selRect.left, selRect.top,
selRect.width, selRect.height );
if ( hasCursor ) {
gtkFillRect( dctx, rInner, cursor );
}
gtkEraseRect( dctx, rInner );
}
/* XP_U16 fontHt = rInner->height; */
/* if ( strstr( scoreBuf, "\n" ) ) { */
/* fontHt >>= 1; */
/* } */
draw_string_at( dctx, NULL, scoreBuf, fontHt/*-1*/,
rInner, XP_GTK_JUST_CENTER,
&dctx->playerColors[playerNum], cursor );
} /* gtk_draw_score_drawPlayer */
#ifdef XWFEATURE_SCOREONEPASS
static void
gtk_draw_drawRemText( DrawCtx* p_dctx, XP_S16 nTilesLeft,
XP_Bool focussed, XP_Rect* rect )
{
if ( nTilesLeft <= 0 ) {
rect->width = rect->height = 0;
} else {
XP_U16 width, height;
gtkDrawDrawRemText( p_dctx, rect, nTilesLeft, &width, &height, focussed );
rect->width = width;
rect->height = height;
gtkDrawDrawRemText( p_dctx, rect, nTilesLeft, NULL, NULL, focussed );
}
}
static void
gtk_draw_score_drawPlayers( DrawCtx* p_dctx, const XP_Rect* scoreRect,
XP_U16 nPlayers,
DrawScoreInfo playerData[],
XP_Rect playerRects[] )
{
XP_USE( playerData );
XP_USE( p_dctx );
XP_U16 ii;
XP_Rect rect = *scoreRect;
rect.width /= nPlayers;
for ( ii = 0; ii < nPlayers; ++ii ) {
XP_U16 ignoreW, ignoreH;
XP_Rect innerR;
gtk_draw_measureScoreText( p_dctx, &rect, &playerData[ii], &ignoreW,
&ignoreH );
innerR = rect;
innerR.left += 4;
innerR.width -= 8;
gtk_draw_score_drawPlayer( p_dctx, &innerR, &rect, 0, &playerData[ii] );
playerRects[ii] = rect;
rect.left += rect.width;
}
}
#else
static void
gtk_draw_measureRemText( DrawCtx* p_dctx, const XP_Rect* rect, XP_S16 nTilesLeft,
XP_U16* width, XP_U16* height )
@ -918,6 +1029,7 @@ gtk_draw_drawRemText( DrawCtx* p_dctx, const XP_Rect* rInner,
gtkDrawDrawRemText( p_dctx, rInner, nTilesLeft, NULL, NULL, focussed );
} /* gtk_draw_drawRemText */
#endif
static void
formatScoreText( PangoLayout* layout, XP_UCHAR* buf, XP_U16 bufLen,
const DrawScoreInfo* dsi, const XP_Rect* bounds,
@ -1011,67 +1123,6 @@ gtk_draw_measureScoreText( DrawCtx* p_dctx, const XP_Rect* bounds,
dctx->scoreCache[playerNum].fontHt = lineHeight;
} /* gtk_draw_measureScoreText */
static void
gtk_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner,
const XP_Rect* rOuter,
XP_U16 XP_UNUSED(gotPct), const DrawScoreInfo* dsi )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Bool hasCursor = (dsi->flags & CELL_ISCURSOR) != 0;
GdkColor* cursor = NULL;
XP_U16 playerNum = dsi->playerNum;
const XP_UCHAR* scoreBuf = dctx->scoreCache[playerNum].str;
XP_U16 fontHt = dctx->scoreCache[playerNum].fontHt;
if ( hasCursor ) {
cursor = &dctx->cursor;
gtkFillRect( dctx, rOuter, cursor );
}
#ifdef USE_CAIRO
//gdk_cairo_set_source_color( dctx->cr, &dctx->playerColors[playerNum] );
#else
gdk_gc_set_foreground( dctx->drawGC, &dctx->playerColors[playerNum] );
#endif
if ( dsi->selected ) {
XP_Rect selRect = *rOuter;
XP_S16 diff;
if ( dctx->scoreIsVertical ) {
diff = selRect.height - rInner->height;
} else {
diff = selRect.width - rInner->width;
}
if ( diff > 0 ) {
if ( dctx->scoreIsVertical ) {
selRect.height -= diff>>1;
selRect.top += diff>>2;
} else {
selRect.width -= diff>>1;
selRect.left += diff>>2;
}
}
draw_rectangle( dctx, DRAW_WHAT(dctx), dctx->drawGC,
TRUE, selRect.left, selRect.top,
selRect.width, selRect.height );
if ( hasCursor ) {
gtkFillRect( dctx, rInner, cursor );
}
gtkEraseRect( dctx, rInner );
}
/* XP_U16 fontHt = rInner->height; */
/* if ( strstr( scoreBuf, "\n" ) ) { */
/* fontHt >>= 1; */
/* } */
draw_string_at( dctx, NULL, scoreBuf, fontHt/*-1*/,
rInner, XP_GTK_JUST_CENTER,
&dctx->playerColors[playerNum], cursor );
} /* gtk_draw_score_drawPlayer */
static void
gtk_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect,
XP_S16 score, XP_U16 XP_UNUSED(playerNum),
@ -1297,10 +1348,15 @@ gtkDrawCtxtMake( GtkWidget* drawing_area, GtkAppGlobals* globals )
SET_VTABLE_ENTRY( dctx->vtable, draw_drawBoardArrow, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_scoreBegin, gtk );
#ifdef XWFEATURE_SCOREONEPASS
SET_VTABLE_ENTRY( dctx->vtable, draw_drawRemText, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_score_drawPlayers, gtk );
#else
SET_VTABLE_ENTRY( dctx->vtable, draw_measureRemText, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawRemText, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_measureScoreText, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_score_drawPlayer, gtk );
#endif
SET_VTABLE_ENTRY( dctx->vtable, draw_score_pendingScore, gtk );
SET_VTABLE_ENTRY( dctx->vtable, draw_drawTimer, gtk );