fold hint-region-drag into dragdrpp, saving a bunch of code and

gaining scrolling during drag on small screens.
This commit is contained in:
ehouse 2008-03-13 12:23:22 +00:00
parent 5c8756856d
commit d00aa75a12
4 changed files with 274 additions and 265 deletions

View file

@ -1,6 +1,6 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ /* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* /*
* Copyright 1997 - 2007 by Eric House (xwords@eehouse.org). All rights * Copyright 1997 - 2008 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -113,8 +113,6 @@ static XP_Bool board_moveArrow( BoardCtxt* board, XP_Key cursorKey );
#ifdef POINTER_SUPPORT #ifdef POINTER_SUPPORT
static void drawDragTileIf( BoardCtxt* board ); static void drawDragTileIf( BoardCtxt* board );
#endif #endif
static XP_Bool holdsPendingTile( BoardCtxt* board,
XP_U16 pencol, XP_U16 penrow );
#ifdef KEY_SUPPORT #ifdef KEY_SUPPORT
static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey, static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey,
@ -128,7 +126,6 @@ static XP_Bool invalFocusOwner( BoardCtxt* board );
#endif #endif
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row ); static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row );
static void invalCurHintRect( BoardCtxt* board, XP_U16 player );
static void clearCurHintRect( BoardCtxt* board ); static void clearCurHintRect( BoardCtxt* board );
#else #else
@ -508,7 +505,7 @@ invalSelTradeWindow( BoardCtxt* board )
} /* invalSelTradeWindow */ } /* invalSelTradeWindow */
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV #if defined POINTER_SUPPORT || defined KEYBOARD_NAV
static void void
hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType ) hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType )
{ {
MiniWindowStuff* stuff = &board->miniWindowStuff[winType]; MiniWindowStuff* stuff = &board->miniWindowStuff[winType];
@ -737,22 +734,19 @@ timerFiredForPen( BoardCtxt* board )
const XP_UCHAR* text = (XP_UCHAR*)NULL; const XP_UCHAR* text = (XP_UCHAR*)NULL;
XP_UCHAR buf[80]; XP_UCHAR buf[80];
if ( (board->penDownObject == OBJ_BOARD) && !dragDropInProgress(board) if ( board->penDownObject == OBJ_BOARD ) {
#ifdef XWFEATURE_SEARCHLIMIT if ( !dragDropInProgress( board ) || !dragDropHasMoved( board ) ) {
&& !board->hintDragInProgress XP_U16 col, row;
#endif XWBonusType bonus;
) {
XP_U16 col, row;
XWBonusType bonus;
coordToCell( board, board->penDownX, board->penDownY, &col, coordToCell( board, board->penDownX, board->penDownY, &col,
&row ); &row );
bonus = util_getSquareBonus(board->util, board->model, col, row); bonus = util_getSquareBonus(board->util, board->model, col, row);
if ( bonus != BONUS_NONE ) { if ( bonus != BONUS_NONE ) {
text = draw_getMiniWText( board->draw, (XWMiniTextType)bonus ); text = draw_getMiniWText( board->draw, (XWMiniTextType)bonus );
}
board->penTimerFired = XP_TRUE;
} }
board->penTimerFired = XP_TRUE;
} else if ( board->penDownObject == OBJ_SCORE ) { } else if ( board->penDownObject == OBJ_SCORE ) {
XP_S16 player; XP_S16 player;
LocalPlayer* lp; LocalPlayer* lp;
@ -1027,7 +1021,7 @@ invalCellsWithTiles( BoardCtxt* board )
return board->needsDrawing; return board->needsDrawing;
} /* invalCellsWithTiles */ } /* invalCellsWithTiles */
static void void
checkScrollCell( void* p_board, XP_U16 col, XP_U16 row ) checkScrollCell( void* p_board, XP_U16 col, XP_U16 row )
{ {
BoardCtxt* board = (BoardCtxt*)p_board; BoardCtxt* board = (BoardCtxt*)p_board;
@ -1965,6 +1959,7 @@ moveTileToArrowLoc( BoardCtxt* board, XP_U8 index )
} }
return result; return result;
} /* moveTileToArrowLoc */ } /* moveTileToArrowLoc */
#endif
static void static void
makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text, makeMiniWindowForText( BoardCtxt* board, const XP_UCHAR* text,
@ -2031,55 +2026,46 @@ figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row )
{ {
HintAtts result = HINT_BORDER_NONE; HintAtts result = HINT_BORDER_NONE;
if ( board->trayVisState == TRAY_REVEALED && board->gi->allowHintRect ) { /* while lets us break to exit... */
BdHintLimits limits = board->limits[board->selPlayer]; while ( board->trayVisState == TRAY_REVEALED && board->gi->allowHintRect ) {
BdHintLimits limits;
/* while lets us break to exit... */ if ( dragDropGetHintLimits( board, &limits ) ) {
while ( board->hasHintRect[board->selPlayer] /* do nothing */
|| board->hintDragInProgress ) { } else if ( board->hasHintRect[board->selPlayer] ) {
if ( col < limits.left ) break; limits = board->limits[board->selPlayer];
if ( row < limits.top ) break; } else {
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; 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; return result;
} /* figureHintAtts */ } /* figureHintAtts */
static XP_Bool void
startHintRegionDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_Bool needsRedraw = XP_FALSE;
XP_U16 col, row;
coordToCell( board, x, y, &col, &row );
board->hintDragStartCol = board->hintDragCurCol = col;
board->hintDragStartRow = board->hintDragCurRow = row;
return needsRedraw;
} /* startHintRegionDrag */
static void
invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB, invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
XP_U16 rowB ) XP_U16 rowB )
{ {
@ -2114,7 +2100,7 @@ invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
} }
} /* invalCellRegion */ } /* invalCellRegion */
static void void
invalCurHintRect( BoardCtxt* board, XP_U16 player ) invalCurHintRect( BoardCtxt* board, XP_U16 player )
{ {
BdHintLimits* limits = &board->limits[player]; BdHintLimits* limits = &board->limits[player];
@ -2129,122 +2115,14 @@ clearCurHintRect( BoardCtxt* board )
board->hasHintRect[board->selPlayer] = XP_FALSE; board->hasHintRect[board->selPlayer] = XP_FALSE;
} /* clearCurHintRect */ } /* clearCurHintRect */
static void
setHintRect( BoardCtxt* board )
{
BdHintLimits limits;
if ( board->hintDragStartRow < board->hintDragCurRow ) {
limits.top = board->hintDragStartRow;
limits.bottom = board->hintDragCurRow;
} else {
limits.top = board->hintDragCurRow;
limits.bottom = board->hintDragStartRow;
}
if ( board->hintDragStartCol < board->hintDragCurCol ) {
limits.left = board->hintDragStartCol;
limits.right = board->hintDragCurCol;
} else {
limits.left = board->hintDragCurCol;
limits.right = board->hintDragStartCol;
}
board->limits[board->selPlayer] = limits;
board->hasHintRect[board->selPlayer] = XP_TRUE;
} /* setHintRect */
static void
invalHintRectDiffs( BoardCtxt* board, BdHintLimits* newLim,
BdHintLimits* oldLim )
{
/* These two regions will generally have close to 50% of their borders in
common. Try not to inval what needn't be inval'd. But at the moment
performance seems good enough without adding the complexity and new
bugs... */
invalCellRegion( board, newLim->left, newLim->top,
newLim->right, newLim->bottom );
invalCellRegion( board, oldLim->left, oldLim->top,
oldLim->right, oldLim->bottom );
/* The challenge in doing a smarter diff is that some squares need to be
invalidated even if they're part of the borders of both limits rects,
in particular if one is a corner of one and just a side of another.
One simple but expensive way of accounting for this would be to call
figureHintAtts() on each square in the borders of both rects and
invalidate when the hintAttributes aren't the same for both. That
misses an opportunity to avoid doing any calculations on those border
squares that clearly haven't changed at all.
*/
} /* invalHintRectDiffs */
static XP_Bool static XP_Bool
continueHintRegionDrag( BoardCtxt* board, XP_U16 x, XP_U16 y ) handlePenDownOnBoard( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
XP_Bool needsRedraw = XP_FALSE;
XP_U16 col, row;
if ( coordToCell( board, x, y, &col, &row ) ) {
XP_U16 selPlayer = board->selPlayer;
checkScrollCell( board, col, row );
if ( col != board->hintDragCurCol || row != board->hintDragCurRow ) {
BdHintLimits oldHL;
needsRedraw = XP_TRUE;
board->hintDragInProgress = XP_TRUE;
/* Now that we've moved, this isn't a timer thing. Clean up any
artifacts. */
board->penTimerFired = XP_FALSE;
if ( valHintMiniWindowActive( board ) ) {
hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT );
}
board->hintDragCurCol = col;
board->hintDragCurRow = row;
oldHL = board->limits[selPlayer];
setHintRect( board );
invalHintRectDiffs( board, &board->limits[selPlayer], &oldHL );
}
}
return needsRedraw;
} /* continueHintRegionDrag */
static XP_Bool
finishHintRegionDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
XP_Bool needsRedraw = XP_FALSE;
XP_Bool makeActive;
XP_ASSERT( board->hintDragInProgress );
needsRedraw = continueHintRegionDrag( board, x, y );
/* Now check if the whole drag ended above where it started. If yes, it
means erase! */
makeActive = board->hintDragStartRow <= board->hintDragCurRow;
board->hasHintRect[board->selPlayer] = makeActive;
if ( !makeActive ) {
invalCurHintRect( board, board->selPlayer );
needsRedraw = XP_TRUE;
}
board_resetEngine( board );
return needsRedraw;
} /* finishHintRegionDrag */
#endif
static XP_Bool
handlePenDownOnBoard( BoardCtxt* board, XP_U16 x, XP_U16 y )
{ {
XP_Bool result = XP_FALSE; XP_Bool result = XP_FALSE;
XP_U16 col, row; XP_U16 col, row;
/* Start a timer no matter what. After it fires we'll decide whether it's /* Start a timer no matter what. After it fires we'll decide whether it's
appropriate to handle it. No. That's too expensive */ appropriate to handle it. No. That's too expensive */
if ( TRADE_IN_PROGRESS(board) && ptOnTradeWindow( board, x, y ) ) { if ( TRADE_IN_PROGRESS(board) && ptOnTradeWindow( board, xx, yy ) ) {
return XP_FALSE; return XP_FALSE;
} }
util_setTimer( board->util, TIMER_PENDOWN, 0, p_board_timerFired, board ); util_setTimer( board->util, TIMER_PENDOWN, 0, p_board_timerFired, board );
@ -2252,17 +2130,11 @@ handlePenDownOnBoard( BoardCtxt* board, XP_U16 x, XP_U16 y )
/* As a first cut, you start a hint-region drag unless the cell is /* As a first cut, you start a hint-region drag unless the cell is
occupied by a non-committed cell. */ occupied by a non-committed cell. */
coordToCell( board, x, y, &col, &row ); coordToCell( board, xx, yy, &col, &row );
if ( (board->trayVisState == TRAY_REVEALED) if ( (board->trayVisState == TRAY_REVEALED)
&& !board->tradeInProgress[board->selPlayer] && !board->tradeInProgress[board->selPlayer] ) {
&& holdsPendingTile( board, col, row ) ) { result = dragDropStart( board, OBJ_BOARD, xx, yy );
result = dragDropStart( board, OBJ_BOARD, col, row );
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->gi->allowHintRect
&& (board->trayVisState == TRAY_REVEALED) ) {
result = startHintRegionDrag( board, x, y );
} }
#endif
return result; return result;
} /* handlePenDownOnBoard */ } /* handlePenDownOnBoard */
@ -2403,19 +2275,10 @@ board_handlePenDown( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* handled )
#endif #endif
XP_Bool XP_Bool
board_handlePenMove( BoardCtxt* board, XP_U16 x, XP_U16 y ) board_handlePenMove( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{ {
XP_Bool result = XP_FALSE; XP_Bool result = dragDropInProgress(board)
&& dragDropContinue( board, xx, yy );
if ( dragDropInProgress(board) ) {
result = dragDropContinue( board, x, y ) != 0;
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->gi->allowHintRect
&& board->trayVisState == TRAY_REVEALED ) {
result = continueHintRegionDrag( board, x, y );
#endif
}
return result; return result;
} /* board_handlePenMove */ } /* board_handlePenMove */
@ -2506,7 +2369,7 @@ tryMoveArrow( BoardCtxt* board, XP_U16 col, XP_U16 row )
return result; return result;
} /* tryMoveArrow */ } /* tryMoveArrow */
static XP_Bool XP_Bool
holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow ) holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow )
{ {
Tile tile; Tile tile;
@ -2584,16 +2447,12 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
draw = dragDropEnd( board, x, y, &dragged ); draw = dragDropEnd( board, x, y, &dragged );
} }
if ( dragged ) { if ( dragged ) {
#ifdef XWFEATURE_SEARCHLIMIT /* do nothing further */
} else if ( board->hintDragInProgress ) {
XP_ASSERT( board->gi->allowHintRect );
draw = finishHintRegionDrag( board, x, y ) || draw;
#endif
} else if ( board->penTimerFired ) { } else if ( board->penTimerFired ) {
if ( valHintMiniWindowActive( board ) ) { if ( valHintMiniWindowActive( board ) ) {
hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT ); hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT );
draw = XP_TRUE;
} }
draw = XP_TRUE; /* might have cancelled a drag */
/* Need to clean up if there's been any dragging happening */ /* Need to clean up if there's been any dragging happening */
board->penTimerFired = XP_FALSE; board->penTimerFired = XP_FALSE;
} else { } else {
@ -2635,9 +2494,6 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
} }
} }
#ifdef XWFEATURE_SEARCHLIMIT
board->hintDragInProgress = XP_FALSE;
#endif
return draw; return draw;
} /* board_handlePenUp */ } /* board_handlePenUp */
#endif /* #ifdef POINTER_SUPPORT */ #endif /* #ifdef POINTER_SUPPORT */

View file

@ -43,12 +43,24 @@ typedef struct _DragObjInfo {
} u; } u;
} DragObjInfo; } DragObjInfo;
typedef enum {
DT_NONE
,DT_DIVIDER
,DT_TILE
#ifdef XWFEATURE_SEARCHLIMIT
,DT_HINTRGN
#endif
} DragType;
typedef struct DragState { typedef struct DragState {
XP_Bool dragInProgress; DragType dtype;
XP_Bool dividerOnly; /* special case; most other stuff ignored */
XP_Bool didMove; /* there was change during the drag; not a XP_Bool didMove; /* there was change during the drag; not a
tap */ tap */
XP_Bool isBlank; /* cache rather than lookup in model */ XP_Bool isBlank; /* cache rather than lookup in model */
#ifdef XWFEATURE_SEARCHLIMIT
/* XP_Bool hintRectInvalidated; /\* only inval cur rect once after start drag *\/ */
#endif
Tile tile; /* cache rather than lookup in model */ Tile tile; /* cache rather than lookup in model */
DragObjInfo start; DragObjInfo start;
DragObjInfo cur; DragObjInfo cur;
@ -175,10 +187,6 @@ struct BoardCtxt {
XP_Bool showColors; XP_Bool showColors;
#ifdef XWFEATURE_SEARCHLIMIT #ifdef XWFEATURE_SEARCHLIMIT
XP_U16 hintDragStartCol, hintDragStartRow;
XP_U16 hintDragCurCol, hintDragCurRow;
XP_Bool hintDragInProgress;
XP_Bool hasHintRect[MAX_NUM_PLAYERS]; XP_Bool hasHintRect[MAX_NUM_PLAYERS];
BdHintLimits limits[MAX_NUM_PLAYERS]; BdHintLimits limits[MAX_NUM_PLAYERS];
#endif #endif
@ -211,20 +219,33 @@ XP_Bool coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP,
XP_U16* rowP ); XP_U16* rowP );
XP_Bool cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool inclPending ); XP_Bool inclPending );
XP_Bool holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow );
XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_U16 tileIndex, Tile blankFace ); XP_U16 tileIndex, Tile blankFace );
void invalTilesUnderRect( BoardCtxt* board, XP_Rect* rect ); void invalTilesUnderRect( BoardCtxt* board, XP_Rect* rect );
void invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
XP_U16 rowB );
void invalDragObj( BoardCtxt* board, const DragObjInfo* di ); void invalDragObj( BoardCtxt* board, const DragObjInfo* di );
void invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex ); void invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex );
void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1, void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
XP_U16 tileIndex2 ); XP_U16 tileIndex2 );
#ifdef XWFEATURE_SEARCHLIMIT
void invalCurHintRect( BoardCtxt* board, XP_U16 player );
#endif
void hideMiniWindow( BoardCtxt* board, XP_Bool destroy,
MiniWindowType winType );
void moveTileInTray( BoardCtxt* board, XP_U16 moveTo, XP_U16 moveFrom ); void moveTileInTray( BoardCtxt* board, XP_U16 moveTo, XP_U16 moveFrom );
XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank, XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
XP_Bitmap* bitmap, XP_S16* value, XP_Bitmap* bitmap, XP_S16* value,
XP_UCHAR* buf, XP_U16 len ); XP_UCHAR* buf, XP_U16 len );
XP_Bool dividerMoved( BoardCtxt* board, XP_U8 newLoc ); XP_Bool dividerMoved( BoardCtxt* board, XP_U8 newLoc );
void checkScrollCell( void* p_board, XP_U16 col, XP_U16 row );
#ifdef KEYBOARD_NAV #ifdef KEYBOARD_NAV
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,
XP_Bool preflightOnly, XP_Bool* up ); XP_Bool preflightOnly, XP_Bool* up );

View file

@ -23,38 +23,60 @@ extern "C" {
#endif #endif
#include "dragdrpp.h" #include "dragdrpp.h"
#include "game.h"
static XP_Bool dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy, static XP_Bool dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
BoardObjectType* onWhichP ); BoardObjectType* onWhichP );
static void invalDragObjRange( BoardCtxt* board, const DragObjInfo* from, static void invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
const DragObjInfo* to ); const DragObjInfo* to );
static void invalHintRectDiffs( BoardCtxt* board, const DragObjInfo* cur,
const DragObjInfo* nxt );
static void setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits );
XP_Bool XP_Bool
dragDropInProgress( const BoardCtxt* board ) dragDropInProgress( const BoardCtxt* board )
{ {
const DragState* ds = &board->dragState; const DragState* ds = &board->dragState;
/* LOG_RETURNF( "%d", ds->dragInProgress ); */ /* LOG_RETURNF( "%d", ds->dragInProgress ); */
return ds->dragInProgress; return ds->dtype != DT_NONE;
} } /* dragDropInProgress */
XP_Bool
dragDropHasMoved( const BoardCtxt* board )
{
return dragDropInProgress(board) && board->dragState.didMove;
} /* dragDropHasMoved */
static XP_Bool static XP_Bool
ddStartBoard( BoardCtxt* board, XP_U16 col, XP_U16 row ) ddStartBoard( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{ {
DragState* ds = &board->dragState; DragState* ds = &board->dragState;
XP_Bool ignore, found; XP_Bool found;
XP_U16 modelc, modelr; XP_U16 col, row;
found = coordToCell( board, xx, yy, &col, &row );
XP_ASSERT( found );
if ( holdsPendingTile( board, col, row ) ) {
XP_U16 modelc, modelr;
XP_Bool ignore;
ds->dtype = DT_TILE;
flipIf( board, col, row, &modelc, &modelr );
found = model_getTile( board->model, modelc, modelr, XP_TRUE,
board->selPlayer, &ds->tile, &ds->isBlank,
&ignore, &ignore );
XP_ASSERT( found );
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->gi->allowHintRect ) {
ds->dtype = DT_HINTRGN;
#endif
}
ds->start.u.board.col = col; ds->start.u.board.col = col;
ds->start.u.board.row = row; ds->start.u.board.row = row;
flipIf( board, col, row, &modelc, &modelr ); return ds->dtype != DT_NONE;
found = model_getTile( board->model, modelc, modelr, XP_TRUE,
board->selPlayer, &ds->tile, &ds->isBlank,
&ignore, &ignore );
XP_ASSERT( found );
return XP_TRUE;
} /* ddStartBoard */ } /* ddStartBoard */
static XP_Bool static XP_Bool
@ -69,9 +91,10 @@ ddStartTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
if ( canDrag ) { if ( canDrag ) {
XP_S16 selPlayer = board->selPlayer; XP_S16 selPlayer = board->selPlayer;
if ( onDivider ) { if ( onDivider ) {
ds->dividerOnly = XP_TRUE;
board->dividerInvalid = XP_TRUE; board->dividerInvalid = XP_TRUE;
ds->start.u.tray.index = board->dividerLoc[selPlayer]; ds->start.u.tray.index = board->dividerLoc[selPlayer];
ds->dtype = DT_DIVIDER;
} else { } else {
Tile tile; Tile tile;
tile = model_getPlayerTile( board->model, selPlayer, index ); tile = model_getPlayerTile( board->model, selPlayer, index );
@ -84,6 +107,8 @@ ddStartTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
/* during drag the moving tile is drawn as selected, so inval /* during drag the moving tile is drawn as selected, so inval
currently selected tile. */ currently selected tile. */
board_invalTrayTiles( board, board->traySelBits[selPlayer] ); board_invalTrayTiles( board, board->traySelBits[selPlayer] );
ds->dtype = DT_TILE;
} }
} }
@ -115,7 +140,6 @@ dragDropStart( BoardCtxt* board, BoardObjectType obj, XP_U16 x, XP_U16 y )
if ( result ) { if ( result ) {
ds->cur = ds->start; ds->cur = ds->start;
invalDragObj( board, &ds->start ); invalDragObj( board, &ds->start );
ds->dragInProgress = XP_TRUE;
} }
return result; return result;
@ -159,9 +183,26 @@ dragDropEnd( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool* dragged )
/* If we've dropped on something, put the tile there! Since we /* If we've dropped on something, put the tile there! Since we
don't remove it from its earlier location until it's dropped, don't remove it from its earlier location until it's dropped,
we need to specify where it's coming from. */ we need to specify where it's coming from. */
if ( ds->dividerOnly ) { if ( ds->dtype == DT_DIVIDER ) {
board->dividerInvalid = XP_TRUE; board->dividerInvalid = XP_TRUE;
/* nothing to do */ /* nothing to do */
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( ds->dtype == DT_HINTRGN ) {
if ( OBJ_BOARD == newObj && ds->didMove ) {
XP_Bool makeActive = ds->start.u.board.row <= ds->cur.u.board.row;
board->hasHintRect[board->selPlayer] = makeActive;
if ( makeActive ) {
setLimitsFrom( board, &board->limits[board->selPlayer] );
} else {
invalHintRectDiffs( board, &ds->cur, NULL );
}
board_resetEngine( board );
} else {
/* return it to whatever it was */
invalHintRectDiffs( board, &ds->cur, NULL );
invalCurHintRect( board, board->selPlayer );
}
#endif
} else { } else {
XP_U16 mod_startc, mod_startr; XP_U16 mod_startc, mod_startr;
@ -208,7 +249,7 @@ dragDropEnd( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool* dragged )
invalDragObj( board, &ds->cur ); invalDragObj( board, &ds->cur );
invalDragObj( board, &ds->start ); invalDragObj( board, &ds->start );
} }
ds->dragInProgress = XP_FALSE; ds->dtype = DT_NONE;
return XP_TRUE; return XP_TRUE;
} /* dragDropEnd */ } /* dragDropEnd */
@ -217,7 +258,7 @@ XP_Bool
dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row ) dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row )
{ {
const DragState* ds = &board->dragState; const DragState* ds = &board->dragState;
XP_Bool found = !ds->dividerOnly && ds->cur.obj == OBJ_BOARD; XP_Bool found = ds->dtype == DT_TILE && ds->cur.obj == OBJ_BOARD;
if ( found ) { if ( found ) {
*col = ds->cur.u.board.col; *col = ds->cur.u.board.col;
*row = ds->cur.u.board.row; *row = ds->cur.u.board.row;
@ -230,8 +271,7 @@ dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool* isOrigin ) XP_Bool* isOrigin )
{ {
const DragState* ds = &board->dragState; const DragState* ds = &board->dragState;
XP_Bool result = dragDropInProgress( board ) && !ds->dividerOnly XP_Bool result = ds->dtype == DT_TILE && ds->cur.obj == OBJ_BOARD;
&& ds->cur.obj == OBJ_BOARD;
if ( result ) { if ( result ) {
const DragState* ds = &board->dragState; const DragState* ds = &board->dragState;
if ( (ds->cur.obj == OBJ_BOARD) && (ds->cur.u.board.col == col) if ( (ds->cur.obj == OBJ_BOARD) && (ds->cur.u.board.col == col)
@ -255,7 +295,7 @@ dragDropGetTrayChanges( const BoardCtxt* board, XP_U16* rmvdIndx,
{ {
const DragState* ds = &board->dragState; const DragState* ds = &board->dragState;
*addedIndx = *rmvdIndx = MAX_TRAY_TILES; /* too big means ignore me */ *addedIndx = *rmvdIndx = MAX_TRAY_TILES; /* too big means ignore me */
if ( dragDropInProgress( board ) && !ds->dividerOnly ) { if ( ds->dtype == DT_TILE ) {
if ( OBJ_TRAY == ds->start.obj ) { if ( OBJ_TRAY == ds->start.obj ) {
*rmvdIndx = ds->start.u.tray.index; *rmvdIndx = ds->start.u.tray.index;
} }
@ -265,10 +305,20 @@ dragDropGetTrayChanges( const BoardCtxt* board, XP_U16* rmvdIndx,
} }
} }
XP_Bool
dragDropGetHintLimits( const BoardCtxt* board, BdHintLimits* limits )
{
XP_Bool result = board->dragState.dtype == DT_HINTRGN;
if ( result ) {
setLimitsFrom( board, limits );
}
return result;
}
XP_Bool XP_Bool
dragDropIsDividerDrag( const BoardCtxt* board ) dragDropIsDividerDrag( const BoardCtxt* board )
{ {
return dragDropInProgress( board ) && board->dragState.dividerOnly; return board->dragState.dtype == DT_DIVIDER;
} }
void void
@ -276,12 +326,44 @@ dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank )
{ {
const DragState* ds = &board->dragState; const DragState* ds = &board->dragState;
XP_ASSERT( dragDropInProgress( board ) ); XP_ASSERT( dragDropInProgress( board ) );
XP_ASSERT( !ds->dividerOnly ); XP_ASSERT( ds->dtype == DT_TILE );
XP_ASSERT ( OBJ_BOARD == ds->start.obj || OBJ_TRAY == ds->start.obj ); XP_ASSERT ( OBJ_BOARD == ds->start.obj || OBJ_TRAY == ds->start.obj );
*tile = ds->tile; *tile = ds->tile;
*isBlank = ds->isBlank; *isBlank = ds->isBlank;
} }
static void
invalHintRectDiffs( BoardCtxt* board, const DragObjInfo* cur,
const DragObjInfo* nxt )
{
XP_U16 startCol = board->dragState.start.u.board.col;
XP_U16 startRow = board->dragState.start.u.board.row;
/* These two regions will generally have close to 50% of their borders in
common. Try not to inval what needn't be inval'd. But at the moment
performance seems good enough without adding the complexity and new
bugs...
The challenge in doing a smarter diff is that some squares need to be
invalidated even if they're part of the borders of both limits rects,
in particular if one is a corner of one and just a side of another.
One simple but expensive way of accounting for this would be to call
figureHintAtts() on each square in the borders of both rects and
invalidate when the hintAttributes aren't the same for both. That
misses an opportunity to avoid doing any calculations on those border
squares that clearly haven't changed at all.
*/
invalCellRegion( board, startCol, startRow, cur->u.board.col,
cur->u.board.row );
if ( !!nxt ) {
BdHintLimits limits;
setLimitsFrom( board, &limits );
invalCellRegion( board, startCol, startRow, nxt->u.board.col,
nxt->u.board.row );
}
}
static XP_Bool static XP_Bool
dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy, dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
BoardObjectType* onWhichP ) BoardObjectType* onWhichP )
@ -289,13 +371,14 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
XP_Bool moving = XP_FALSE; XP_Bool moving = XP_FALSE;
DragObjInfo newInfo; DragObjInfo newInfo;
DragState* ds = &board->dragState; DragState* ds = &board->dragState;
XP_Bool doMore = XP_FALSE;
if ( !pointOnSomething( board, xx, yy, &newInfo.obj ) ) { if ( !pointOnSomething( board, xx, yy, &newInfo.obj ) ) {
newInfo.obj = OBJ_NONE; newInfo.obj = OBJ_NONE;
} }
*onWhichP = newInfo.obj; *onWhichP = newInfo.obj;
if ( ds->dividerOnly ) { if ( ds->dtype == DT_DIVIDER ) {
if ( OBJ_TRAY == newInfo.obj ) { if ( OBJ_TRAY == newInfo.obj ) {
XP_U16 newloc; XP_U16 newloc;
XP_U16 scale = board->trayScaleH; XP_U16 scale = board->trayScaleH;
@ -307,39 +390,78 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
moving = dividerMoved( board, newloc ); moving = dividerMoved( board, newloc );
} }
} else { } else {
if ( newInfo.obj == OBJ_BOARD ) { /* If scrolling is possible, we can't trust pointOnSomething. So
(void)coordToCell( board, xx, yy, &newInfo.u.board.col, check coordToCell. */
&newInfo.u.board.row ); if( coordToCell( board, xx, yy, &newInfo.u.board.col,
moving = (OBJ_TRAY == ds->cur.obj) &newInfo.u.board.row ) ) {
|| (newInfo.u.board.col != ds->cur.u.board.col) newInfo.obj = OBJ_BOARD;
|| (newInfo.u.board.row != ds->cur.u.board.row); doMore = XP_TRUE;
} else if ( newInfo.obj == OBJ_TRAY ) { } else {
XP_Bool onDivider; doMore = OBJ_TRAY == newInfo.obj;
XP_S16 index = pointToTileIndex( board, xx, yy, &onDivider ); }
if ( !onDivider ) { }
if ( index < 0 ) { /* negative means onto empty part of tray.
Force left. */ if ( doMore ) {
index = model_getNumTilesInTray( board->model, #ifdef XWFEATURE_SEARCHLIMIT
board->selPlayer ); if ( ds->dtype == DT_HINTRGN && newInfo.obj != OBJ_BOARD ) {
if ( OBJ_TRAY == ds->start.obj ) { /* do nothing */
--index; /* dragging right into space */ #endif
} else {
if ( newInfo.obj == OBJ_BOARD ) {
(void)coordToCell( board, xx, yy, &newInfo.u.board.col,
&newInfo.u.board.row );
moving = (newInfo.u.board.col != ds->cur.u.board.col)
|| (newInfo.u.board.row != ds->cur.u.board.row);
if ( moving ) {
checkScrollCell( board, newInfo.u.board.col, newInfo.u.board.row );
}
moving = moving || (OBJ_TRAY == ds->cur.obj);
} else if ( newInfo.obj == OBJ_TRAY ) {
XP_Bool onDivider;
XP_S16 index = pointToTileIndex( board, xx, yy, &onDivider );
if ( !onDivider ) {
if ( index < 0 ) { /* negative means onto empty part of tray.
Force left. */
index = model_getNumTilesInTray( board->model,
board->selPlayer );
if ( OBJ_TRAY == ds->start.obj ) {
--index; /* dragging right into space */
}
}
moving = (OBJ_BOARD == ds->cur.obj)
|| (index != ds->cur.u.tray.index);
if ( moving ) {
newInfo.u.tray.index = index;
} }
} }
moving = (OBJ_BOARD == ds->cur.obj)
|| (index != ds->cur.u.tray.index);
if ( moving ) {
newInfo.u.tray.index = index;
}
} }
}
if ( moving ) { if ( moving ) {
invalDragObjRange( board, &ds->cur, &newInfo ); if ( ds->dtype == DT_TILE ) {
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) ); invalDragObjRange( board, &ds->cur, &newInfo );
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( ds->dtype == DT_HINTRGN ) {
invalHintRectDiffs( board, &ds->cur, &newInfo );
if ( !ds->didMove ) { /* first time through */
invalCurHintRect( board, board->selPlayer );
}
#endif
}
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
}
} }
} }
if ( moving ) { if ( moving ) {
if ( !ds->didMove ) {
/* This is the first time we've moved!!! Kill any future timers,
and if there's a window up kill it.*/
board->penTimerFired = XP_FALSE;
if ( valHintMiniWindowActive( board ) ) {
hideMiniWindow( board, XP_TRUE, MINIWINDOW_VALHINT );
}
}
ds->didMove = XP_TRUE; ds->didMove = XP_TRUE;
} }
@ -365,6 +487,16 @@ invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
} }
} }
static void
setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits )
{
const DragState* ds = &board->dragState;
limits->left = XP_MIN( ds->start.u.board.col, ds->cur.u.board.col );
limits->right = XP_MAX( ds->start.u.board.col, ds->cur.u.board.col );
limits->top = XP_MIN( ds->start.u.board.row, ds->cur.u.board.row );
limits->bottom = XP_MAX( ds->start.u.board.row, ds->cur.u.board.row );
}
#ifdef CPLUS #ifdef CPLUS
} }
#endif #endif

View file

@ -29,14 +29,13 @@ extern "C" {
#endif #endif
XP_Bool dragDropInProgress( const BoardCtxt* board ); XP_Bool dragDropInProgress( const BoardCtxt* board );
XP_Bool dragDropHasMoved( const BoardCtxt* board );
/* dragDropStart
* Pass col,row for board, but raw x,y for tray. Yeah, sucks.
*/
XP_Bool dragDropStart( BoardCtxt* board, BoardObjectType obj, XP_Bool dragDropStart( BoardCtxt* board, BoardObjectType obj,
XP_U16 x, XP_U16 y ); XP_U16 xx, XP_U16 yy );
XP_Bool dragDropContinue( BoardCtxt* board, XP_U16 x, XP_U16 y ); XP_Bool dragDropContinue( BoardCtxt* board, XP_U16 xx, XP_U16 yy );
XP_Bool dragDropEnd( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* dragged ); XP_Bool dragDropEnd( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool* dragged );
XP_Bool dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row ); XP_Bool dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row );
XP_Bool dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool* isOrigin ); XP_Bool* isOrigin );
@ -47,6 +46,7 @@ XP_Bool dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
*/ */
void dragDropGetTrayChanges( const BoardCtxt* board, XP_U16* rmvdIndx, void dragDropGetTrayChanges( const BoardCtxt* board, XP_U16* rmvdIndx,
XP_U16* addedIndx ); XP_U16* addedIndx );
XP_Bool dragDropGetHintLimits( const BoardCtxt* board, BdHintLimits* limits );
XP_Bool dragDropIsDividerDrag( const BoardCtxt* board ); XP_Bool dragDropIsDividerDrag( const BoardCtxt* board );
void dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank ); void dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank );