mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-28 09:58:30 +01:00
Implement scrolling during drag via timer rather than by counting on
getting notified when pen is dragged off the board. The latter won't happen if the board is up against the edge of the screen.
This commit is contained in:
parent
1172502b04
commit
1e7bc3839b
4 changed files with 128 additions and 90 deletions
|
@ -444,7 +444,7 @@ board_setYOffset( BoardCtxt* board, XP_U16 offset )
|
|||
} /* board_setYOffset */
|
||||
|
||||
XP_U16
|
||||
board_getYOffset( BoardCtxt* board )
|
||||
board_getYOffset( const BoardCtxt* board )
|
||||
{
|
||||
return board->yOffset;
|
||||
} /* board_getYOffset */
|
||||
|
@ -911,7 +911,7 @@ invalOldPerimeter( BoardCtxt* board )
|
|||
firstRow = board->yOffset + 1;
|
||||
lastRow = board->prevYScrollOffset;
|
||||
} else {
|
||||
XP_U16 nVisible = board->lastVisibleRow - board->yOffset;
|
||||
XP_U16 nVisible = board->lastVisibleRow - board->yOffset + 1;
|
||||
lastRow = board->prevYScrollOffset + nVisible - 1;
|
||||
firstRow = lastRow - diff + 1;
|
||||
}
|
||||
|
@ -928,7 +928,7 @@ invalPerimeter( BoardCtxt* board )
|
|||
XP_U16 lastCol = model_numCols( board->model ) - 1;
|
||||
XP_U16 firstAndLast = (1 << lastCol) | 1;
|
||||
XP_U16 firstRow = board->yOffset;
|
||||
XP_U16 lastRow = board->lastVisibleRow - 1;
|
||||
XP_U16 lastRow = board->lastVisibleRow;
|
||||
|
||||
/* top and bottom rows */
|
||||
board->redrawFlags[firstRow] = ~0;
|
||||
|
@ -1023,9 +1023,8 @@ invalCellsWithTiles( BoardCtxt* board )
|
|||
} /* invalCellsWithTiles */
|
||||
|
||||
XP_Bool
|
||||
checkScrollCell( void* p_board, XP_U16 col, XP_U16 row )
|
||||
checkScrollCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
|
||||
{
|
||||
BoardCtxt* board = (BoardCtxt*)p_board;
|
||||
XP_Rect rect;
|
||||
XP_Bool moved = XP_FALSE;
|
||||
|
||||
|
@ -1048,6 +1047,27 @@ checkScrollCell( void* p_board, XP_U16 col, XP_U16 row )
|
|||
return moved;
|
||||
} /* checkScrollCell */
|
||||
|
||||
XP_Bool
|
||||
onBorderCanScroll( const BoardCtxt* board, XP_U16 row, XP_S16* changeP )
|
||||
{
|
||||
XP_Bool result;
|
||||
XP_S16 change = 0;
|
||||
XP_U16 yOffset = board_getYOffset( board );
|
||||
|
||||
if ( yOffset > 0 && row == yOffset ) {
|
||||
change = -yOffset;
|
||||
} else if ( row == board->lastVisibleRow ) {
|
||||
XP_U16 lastRow = model_numRows(board->model) - 1;
|
||||
change = lastRow - row;
|
||||
}
|
||||
|
||||
result = change != 0;
|
||||
if ( result ) {
|
||||
*changeP = change;
|
||||
}
|
||||
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
|
||||
|
@ -1172,7 +1192,7 @@ cellFocused( const BoardCtxt* board, XP_U16 col, XP_U16 row )
|
|||
focussed = (col == 0)
|
||||
|| (col == model_numCols(board->model) - 1)
|
||||
|| (row == board->yOffset)
|
||||
|| (row == board->lastVisibleRow - 1);
|
||||
|| (row == board->lastVisibleRow);
|
||||
#else
|
||||
focussed = XP_TRUE;
|
||||
#endif
|
||||
|
@ -1208,7 +1228,7 @@ drawBoard( BoardCtxt* board )
|
|||
board->trayVisState == TRAY_REVEALED, &bq );
|
||||
invalBlanksWithNeighbors( board, &bq );
|
||||
|
||||
for ( row = board->yOffset; row < board->lastVisibleRow; ++row ) {
|
||||
for ( row = board->yOffset; row <= board->lastVisibleRow; ++row ) {
|
||||
XP_U16 rowFlags = board->redrawFlags[row];
|
||||
if ( rowFlags != 0 ) {
|
||||
XP_U16 colMask;
|
||||
|
@ -1501,7 +1521,7 @@ setTrayVisState( BoardCtxt* board, XW_TrayVisState newState )
|
|||
invalCurHintRect( board, selPlayer );
|
||||
#endif
|
||||
|
||||
nVisible = board->lastVisibleRow - board->yOffset;
|
||||
nVisible = board->lastVisibleRow - board->yOffset + 1;
|
||||
util_trayHiddenChange( board->util, board->trayVisState, nVisible );
|
||||
}
|
||||
return changed;
|
||||
|
@ -1842,7 +1862,7 @@ figureBoardRect( BoardCtxt* board )
|
|||
/* round down */
|
||||
nVisible = boardBounds.height / boardVScale;
|
||||
boardBounds.height = nVisible * boardVScale;
|
||||
board->lastVisibleRow = nVisible + board->yOffset;
|
||||
board->lastVisibleRow = nVisible + board->yOffset - 1;
|
||||
|
||||
board->boardBounds = boardBounds;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ void board_reset( BoardCtxt* board );
|
|||
|
||||
/* Vertical scroll support; offset is in rows, not pixels */
|
||||
XP_Bool board_setYOffset( BoardCtxt* board, XP_U16 newOffset );
|
||||
XP_U16 board_getYOffset( BoardCtxt* board );
|
||||
XP_U16 board_getYOffset( const BoardCtxt* board );
|
||||
|
||||
void board_setScoreboardLoc( BoardCtxt* board,
|
||||
XP_U16 scoreLeft, XP_U16 scoreTop,
|
||||
|
|
|
@ -57,6 +57,7 @@ typedef struct DragState {
|
|||
DragType dtype;
|
||||
XP_Bool didMove; /* there was change during the drag; not a
|
||||
tap */
|
||||
XP_Bool scrollTimerSet;
|
||||
XP_Bool isBlank; /* cache rather than lookup in model */
|
||||
Tile tile; /* cache rather than lookup in model */
|
||||
DragObjInfo start;
|
||||
|
@ -241,7 +242,8 @@ XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
|
|||
XP_UCHAR* buf, XP_U16 len );
|
||||
XP_Bool dividerMoved( BoardCtxt* board, XP_U8 newLoc );
|
||||
|
||||
XP_Bool checkScrollCell( void* p_board, XP_U16 col, XP_U16 row );
|
||||
XP_Bool checkScrollCell( BoardCtxt* board, XP_U16 col, XP_U16 row );
|
||||
XP_Bool onBorderCanScroll( const BoardCtxt* board, XP_U16 row, XP_S16* change );
|
||||
|
||||
#ifdef KEYBOARD_NAV
|
||||
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,
|
||||
|
|
|
@ -33,6 +33,8 @@ static void invalHintRectDiffs( BoardCtxt* board, const DragObjInfo* cur,
|
|||
const DragObjInfo* nxt );
|
||||
static void setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits );
|
||||
|
||||
static void startScrollTimerIf( BoardCtxt* board );
|
||||
|
||||
XP_Bool
|
||||
dragDropInProgress( const BoardCtxt* board )
|
||||
{
|
||||
|
@ -140,6 +142,7 @@ dragDropStart( BoardCtxt* board, BoardObjectType obj, XP_U16 x, XP_U16 y )
|
|||
if ( result ) {
|
||||
ds->cur = ds->start;
|
||||
invalDragObj( board, &ds->start );
|
||||
startScrollTimerIf( board );
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -219,24 +222,23 @@ dragDropEnd( BoardCtxt* board, XP_U16 xx, XP_U16 yy, XP_Bool* dragged )
|
|||
ds->start.u.tray.index,
|
||||
ds->cur.u.tray.index );
|
||||
}
|
||||
} else if ( newObj == OBJ_BOARD ) {
|
||||
if ( !cellOccupied( board, ds->cur.u.board.col,
|
||||
ds->cur.u.board.row, XP_TRUE ) ) {
|
||||
if ( ds->start.obj == OBJ_TRAY ) {
|
||||
/* moveTileToBoard flips its inputs */
|
||||
(void)moveTileToBoard( board, ds->cur.u.board.col,
|
||||
ds->cur.u.board.row,
|
||||
ds->start.u.tray.index, EMPTY_TILE );
|
||||
} else if ( ds->start.obj == OBJ_BOARD ) {
|
||||
XP_U16 mod_curc, mod_curr;
|
||||
flipIf( board, ds->cur.u.board.col, ds->cur.u.board.row,
|
||||
&mod_curc, &mod_curr );
|
||||
model_moveTileOnBoard( board->model, board->selPlayer,
|
||||
mod_startc, mod_startr, mod_curc,
|
||||
mod_curr );
|
||||
/* inval points tile in case score changed */
|
||||
board_invalTrayTiles( board, 1 << (MAX_TRAY_TILES-1) );
|
||||
}
|
||||
} else if ( (newObj == OBJ_BOARD) &&
|
||||
!cellOccupied( board, ds->cur.u.board.col,
|
||||
ds->cur.u.board.row, XP_TRUE ) ) {
|
||||
if ( ds->start.obj == OBJ_TRAY ) {
|
||||
/* moveTileToBoard flips its inputs */
|
||||
(void)moveTileToBoard( board, ds->cur.u.board.col,
|
||||
ds->cur.u.board.row,
|
||||
ds->start.u.tray.index, EMPTY_TILE );
|
||||
} else if ( ds->start.obj == OBJ_BOARD ) {
|
||||
XP_U16 mod_curc, mod_curr;
|
||||
flipIf( board, ds->cur.u.board.col, ds->cur.u.board.row,
|
||||
&mod_curc, &mod_curr );
|
||||
model_moveTileOnBoard( board->model, board->selPlayer,
|
||||
mod_startc, mod_startr, mod_curc,
|
||||
mod_curr );
|
||||
/* inval points tile in case score changed */
|
||||
board_invalTrayTiles( board, 1 << (MAX_TRAY_TILES-1) );
|
||||
}
|
||||
} else {
|
||||
/* We're returning it to start, so will be re-inserted in tray */
|
||||
|
@ -371,7 +373,6 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
|
|||
XP_Bool moving = XP_FALSE;
|
||||
DragObjInfo newInfo;
|
||||
DragState* ds = &board->dragState;
|
||||
XP_Bool doMore = XP_FALSE;
|
||||
|
||||
if ( !pointOnSomething( board, xx, yy, &newInfo.obj ) ) {
|
||||
newInfo.obj = OBJ_NONE;
|
||||
|
@ -389,76 +390,51 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
|
|||
}
|
||||
moving = dividerMoved( board, newloc );
|
||||
}
|
||||
} else {
|
||||
/* If scrolling is possible, we can't trust pointOnSomething. So
|
||||
check coordToCell. */
|
||||
if( coordToCell( board, xx, yy, &newInfo.u.board.col,
|
||||
&newInfo.u.board.row ) ) {
|
||||
newInfo.obj = OBJ_BOARD;
|
||||
doMore = XP_TRUE;
|
||||
} else {
|
||||
doMore = OBJ_TRAY == newInfo.obj;
|
||||
}
|
||||
}
|
||||
|
||||
if ( doMore ) {
|
||||
#ifdef XWFEATURE_SEARCHLIMIT
|
||||
if ( ds->dtype == DT_HINTRGN && newInfo.obj != OBJ_BOARD ) {
|
||||
} else if ( ds->dtype == DT_HINTRGN && newInfo.obj != OBJ_BOARD ) {
|
||||
/* do nothing */
|
||||
#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)
|
||||
|| (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;
|
||||
} 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)
|
||||
|| (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( moving ) {
|
||||
|
||||
/* This little hack lets us inval twice using the same code but
|
||||
only in the case where scrolling moves tiles. At a minimum
|
||||
it's necessary to inval the old position before a scroll and
|
||||
the new after. Otherwise if the platform scrolls by
|
||||
bit-blitting the dragged object will be scrolled before it's
|
||||
invalidated. */
|
||||
do {
|
||||
if ( ds->dtype == DT_TILE ) {
|
||||
invalDragObjRange( board, &ds->cur, &newInfo );
|
||||
if ( moving ) {
|
||||
if ( ds->dtype == DT_TILE ) {
|
||||
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 );
|
||||
}
|
||||
} else if ( ds->dtype == DT_HINTRGN ) {
|
||||
invalHintRectDiffs( board, &ds->cur, &newInfo );
|
||||
if ( !ds->didMove ) { /* first time through */
|
||||
invalCurHintRect( board, board->selPlayer );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} while ( (newInfo.obj == OBJ_BOARD)
|
||||
&& checkScrollCell( board, newInfo.u.board.col,
|
||||
newInfo.u.board.row ) );
|
||||
|
||||
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
|
||||
}
|
||||
|
||||
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
|
||||
startScrollTimerIf( board );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,6 +482,46 @@ setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits )
|
|||
limits->bottom = XP_MAX( ds->start.u.board.row, ds->cur.u.board.row );
|
||||
}
|
||||
|
||||
static void
|
||||
scrollTimerProc( void* closure, XWTimerReason why )
|
||||
{
|
||||
BoardCtxt* board = (BoardCtxt*)closure;
|
||||
DragState* ds = &board->dragState;
|
||||
XP_ASSERT( why == TIMER_PENDOWN );
|
||||
|
||||
if ( ds->scrollTimerSet ) {
|
||||
XP_S16 change;
|
||||
ds->scrollTimerSet = XP_FALSE;
|
||||
if ( onBorderCanScroll( board, ds->cur.u.board.row, &change ) ) {
|
||||
invalDragObj( board, &ds->cur );
|
||||
ds->cur.u.board.row += (change >0 ? 1 : -1);
|
||||
if ( checkScrollCell( board, ds->cur.u.board.col,
|
||||
ds->cur.u.board.row ) ) {
|
||||
board_draw( board ); /* may fail, e.g. on wince */
|
||||
startScrollTimerIf( board );
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* scrollTimerProc */
|
||||
|
||||
static void
|
||||
startScrollTimerIf( BoardCtxt* board )
|
||||
{
|
||||
DragState* ds = &board->dragState;
|
||||
|
||||
if ( ds->cur.obj == OBJ_BOARD ) {
|
||||
XP_S16 ignore;
|
||||
if ( onBorderCanScroll( board, ds->cur.u.board.row, &ignore ) ) {
|
||||
util_setTimer( board->util, TIMER_PENDOWN, 0,
|
||||
scrollTimerProc, (void*) board );
|
||||
ds->scrollTimerSet = XP_TRUE;
|
||||
} else {
|
||||
/* ignore if we've moved off */
|
||||
ds->scrollTimerSet = XP_FALSE;
|
||||
}
|
||||
}
|
||||
} /* startScrollTimerIf */
|
||||
|
||||
#ifdef CPLUS
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue