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; -*- */
/*
* Copyright 1997 - 2007 by Eric House (xwords@eehouse.org). All rights
* Copyright 1997 - 2008 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* 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
static void drawDragTileIf( BoardCtxt* board );
#endif
static XP_Bool holdsPendingTile( BoardCtxt* board,
XP_U16 pencol, XP_U16 penrow );
#ifdef KEY_SUPPORT
static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey,
@ -128,7 +126,6 @@ static XP_Bool invalFocusOwner( BoardCtxt* board );
#endif
#ifdef XWFEATURE_SEARCHLIMIT
static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row );
static void invalCurHintRect( BoardCtxt* board, XP_U16 player );
static void clearCurHintRect( BoardCtxt* board );
#else
@ -508,7 +505,7 @@ invalSelTradeWindow( BoardCtxt* board )
} /* invalSelTradeWindow */
#if defined POINTER_SUPPORT || defined KEYBOARD_NAV
static void
void
hideMiniWindow( BoardCtxt* board, XP_Bool destroy, MiniWindowType winType )
{
MiniWindowStuff* stuff = &board->miniWindowStuff[winType];
@ -737,22 +734,19 @@ timerFiredForPen( BoardCtxt* board )
const XP_UCHAR* text = (XP_UCHAR*)NULL;
XP_UCHAR buf[80];
if ( (board->penDownObject == OBJ_BOARD) && !dragDropInProgress(board)
#ifdef XWFEATURE_SEARCHLIMIT
&& !board->hintDragInProgress
#endif
) {
XP_U16 col, row;
XWBonusType bonus;
if ( board->penDownObject == OBJ_BOARD ) {
if ( !dragDropInProgress( board ) || !dragDropHasMoved( board ) ) {
XP_U16 col, row;
XWBonusType bonus;
coordToCell( board, board->penDownX, board->penDownY, &col,
&row );
bonus = util_getSquareBonus(board->util, board->model, col, row);
if ( bonus != BONUS_NONE ) {
text = draw_getMiniWText( board->draw, (XWMiniTextType)bonus );
coordToCell( board, board->penDownX, board->penDownY, &col,
&row );
bonus = util_getSquareBonus(board->util, board->model, col, row);
if ( bonus != BONUS_NONE ) {
text = draw_getMiniWText( board->draw, (XWMiniTextType)bonus );
}
board->penTimerFired = XP_TRUE;
}
board->penTimerFired = XP_TRUE;
} else if ( board->penDownObject == OBJ_SCORE ) {
XP_S16 player;
LocalPlayer* lp;
@ -1027,7 +1021,7 @@ invalCellsWithTiles( BoardCtxt* board )
return board->needsDrawing;
} /* invalCellsWithTiles */
static void
void
checkScrollCell( void* p_board, XP_U16 col, XP_U16 row )
{
BoardCtxt* board = (BoardCtxt*)p_board;
@ -1965,6 +1959,7 @@ moveTileToArrowLoc( BoardCtxt* board, XP_U8 index )
}
return result;
} /* moveTileToArrowLoc */
#endif
static void
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;
if ( board->trayVisState == TRAY_REVEALED && board->gi->allowHintRect ) {
BdHintLimits limits = board->limits[board->selPlayer];
/* while lets us break to exit... */
while ( board->hasHintRect[board->selPlayer]
|| board->hintDragInProgress ) {
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
/* 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 */
static XP_Bool
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
void
invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
XP_U16 rowB )
{
@ -2114,7 +2100,7 @@ invalCellRegion( BoardCtxt* board, XP_U16 colA, XP_U16 rowA, XP_U16 colB,
}
} /* invalCellRegion */
static void
void
invalCurHintRect( BoardCtxt* board, XP_U16 player )
{
BdHintLimits* limits = &board->limits[player];
@ -2129,122 +2115,14 @@ clearCurHintRect( BoardCtxt* board )
board->hasHintRect[board->selPlayer] = XP_FALSE;
} /* 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
continueHintRegionDrag( BoardCtxt* board, XP_U16 x, XP_U16 y )
{
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 )
handlePenDownOnBoard( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
XP_Bool result = XP_FALSE;
XP_U16 col, row;
/* Start a timer no matter what. After it fires we'll decide whether it's
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;
}
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
occupied by a non-committed cell. */
coordToCell( board, x, y, &col, &row );
coordToCell( board, xx, yy, &col, &row );
if ( (board->trayVisState == TRAY_REVEALED)
&& !board->tradeInProgress[board->selPlayer]
&& holdsPendingTile( board, col, row ) ) {
result = dragDropStart( board, OBJ_BOARD, col, row );
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->gi->allowHintRect
&& (board->trayVisState == TRAY_REVEALED) ) {
result = startHintRegionDrag( board, x, y );
&& !board->tradeInProgress[board->selPlayer] ) {
result = dragDropStart( board, OBJ_BOARD, xx, yy );
}
#endif
return result;
} /* handlePenDownOnBoard */
@ -2403,19 +2275,10 @@ board_handlePenDown( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* handled )
#endif
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;
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
}
XP_Bool result = dragDropInProgress(board)
&& dragDropContinue( board, xx, yy );
return result;
} /* board_handlePenMove */
@ -2506,7 +2369,7 @@ tryMoveArrow( BoardCtxt* board, XP_U16 col, XP_U16 row )
return result;
} /* tryMoveArrow */
static XP_Bool
XP_Bool
holdsPendingTile( BoardCtxt* board, XP_U16 pencol, XP_U16 penrow )
{
Tile tile;
@ -2584,16 +2447,12 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
draw = dragDropEnd( board, x, y, &dragged );
}
if ( dragged ) {
#ifdef XWFEATURE_SEARCHLIMIT
} else if ( board->hintDragInProgress ) {
XP_ASSERT( board->gi->allowHintRect );
draw = finishHintRegionDrag( board, x, y ) || draw;
#endif
/* do nothing further */
} else if ( board->penTimerFired ) {
if ( valHintMiniWindowActive( board ) ) {
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 */
board->penTimerFired = XP_FALSE;
} 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;
} /* board_handlePenUp */
#endif /* #ifdef POINTER_SUPPORT */

View file

@ -43,12 +43,24 @@ typedef struct _DragObjInfo {
} u;
} DragObjInfo;
typedef enum {
DT_NONE
,DT_DIVIDER
,DT_TILE
#ifdef XWFEATURE_SEARCHLIMIT
,DT_HINTRGN
#endif
} DragType;
typedef struct DragState {
XP_Bool dragInProgress;
XP_Bool dividerOnly; /* special case; most other stuff ignored */
DragType dtype;
XP_Bool didMove; /* there was change during the drag; not a
tap */
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 */
DragObjInfo start;
DragObjInfo cur;
@ -175,10 +187,6 @@ struct BoardCtxt {
XP_Bool showColors;
#ifdef XWFEATURE_SEARCHLIMIT
XP_U16 hintDragStartCol, hintDragStartRow;
XP_U16 hintDragCurCol, hintDragCurRow;
XP_Bool hintDragInProgress;
XP_Bool hasHintRect[MAX_NUM_PLAYERS];
BdHintLimits limits[MAX_NUM_PLAYERS];
#endif
@ -211,20 +219,33 @@ XP_Bool coordToCell( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_U16* colP,
XP_U16* rowP );
XP_Bool cellOccupied( BoardCtxt* board, XP_U16 col, XP_U16 row,
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_U16 tileIndex, Tile blankFace );
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 invalTrayTilesAbove( BoardCtxt* board, XP_U16 tileIndex );
void invalTrayTilesBetween( BoardCtxt* board, XP_U16 tileIndex1,
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 );
XP_UCHAR* getTileDrawInfo( const BoardCtxt* board, Tile tile, XP_Bool isBlank,
XP_Bitmap* bitmap, XP_S16* value,
XP_UCHAR* buf, XP_U16 len );
XP_Bool dividerMoved( BoardCtxt* board, XP_U8 newLoc );
void checkScrollCell( void* p_board, XP_U16 col, XP_U16 row );
#ifdef KEYBOARD_NAV
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey,
XP_Bool preflightOnly, XP_Bool* up );

View file

@ -23,38 +23,60 @@ extern "C" {
#endif
#include "dragdrpp.h"
#include "game.h"
static XP_Bool dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
BoardObjectType* onWhichP );
static void invalDragObjRange( BoardCtxt* board, const DragObjInfo* from,
const DragObjInfo* to );
static void invalHintRectDiffs( BoardCtxt* board, const DragObjInfo* cur,
const DragObjInfo* nxt );
static void setLimitsFrom( const BoardCtxt* board, BdHintLimits* limits );
XP_Bool
dragDropInProgress( const BoardCtxt* board )
{
const DragState* ds = &board->dragState;
/* 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
ddStartBoard( BoardCtxt* board, XP_U16 col, XP_U16 row )
ddStartBoard( BoardCtxt* board, XP_U16 xx, XP_U16 yy )
{
DragState* ds = &board->dragState;
XP_Bool ignore, found;
XP_U16 modelc, modelr;
XP_Bool found;
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.row = row;
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 );
return XP_TRUE;
return ds->dtype != DT_NONE;
} /* ddStartBoard */
static XP_Bool
@ -69,9 +91,10 @@ ddStartTray( BoardCtxt* board, XP_U16 x, XP_U16 y )
if ( canDrag ) {
XP_S16 selPlayer = board->selPlayer;
if ( onDivider ) {
ds->dividerOnly = XP_TRUE;
board->dividerInvalid = XP_TRUE;
ds->start.u.tray.index = board->dividerLoc[selPlayer];
ds->dtype = DT_DIVIDER;
} else {
Tile tile;
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
currently selected tile. */
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 ) {
ds->cur = ds->start;
invalDragObj( board, &ds->start );
ds->dragInProgress = XP_TRUE;
}
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
don't remove it from its earlier location until it's dropped,
we need to specify where it's coming from. */
if ( ds->dividerOnly ) {
if ( ds->dtype == DT_DIVIDER ) {
board->dividerInvalid = XP_TRUE;
/* 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 {
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->start );
}
ds->dragInProgress = XP_FALSE;
ds->dtype = DT_NONE;
return XP_TRUE;
} /* dragDropEnd */
@ -217,7 +258,7 @@ XP_Bool
dragDropGetBoardTile( const BoardCtxt* board, XP_U16* col, XP_U16* row )
{
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 ) {
*col = ds->cur.u.board.col;
*row = ds->cur.u.board.row;
@ -230,8 +271,7 @@ dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
XP_Bool* isOrigin )
{
const DragState* ds = &board->dragState;
XP_Bool result = dragDropInProgress( board ) && !ds->dividerOnly
&& ds->cur.obj == OBJ_BOARD;
XP_Bool result = ds->dtype == DT_TILE && ds->cur.obj == OBJ_BOARD;
if ( result ) {
const DragState* ds = &board->dragState;
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;
*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 ) {
*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
dragDropIsDividerDrag( const BoardCtxt* board )
{
return dragDropInProgress( board ) && board->dragState.dividerOnly;
return board->dragState.dtype == DT_DIVIDER;
}
void
@ -276,12 +326,44 @@ dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank )
{
const DragState* ds = &board->dragState;
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 );
*tile = ds->tile;
*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
dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
BoardObjectType* onWhichP )
@ -289,13 +371,14 @@ 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;
}
*onWhichP = newInfo.obj;
if ( ds->dividerOnly ) {
if ( ds->dtype == DT_DIVIDER ) {
if ( OBJ_TRAY == newInfo.obj ) {
XP_U16 newloc;
XP_U16 scale = board->trayScaleH;
@ -307,39 +390,78 @@ dragDropContinueImpl( BoardCtxt* board, XP_U16 xx, XP_U16 yy,
moving = dividerMoved( board, newloc );
}
} else {
if ( newInfo.obj == OBJ_BOARD ) {
(void)coordToCell( board, xx, yy, &newInfo.u.board.col,
&newInfo.u.board.row );
moving = (OBJ_TRAY == ds->cur.obj)
|| (newInfo.u.board.col != ds->cur.u.board.col)
|| (newInfo.u.board.row != ds->cur.u.board.row);
} 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 */
/* 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 ) {
/* 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);
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 ) {
invalDragObjRange( board, &ds->cur, &newInfo );
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
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 );
}
#endif
}
XP_MEMCPY( &ds->cur, &newInfo, sizeof(ds->cur) );
}
}
}
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;
}
@ -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
}
#endif

View file

@ -29,14 +29,13 @@ extern "C" {
#endif
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_U16 x, XP_U16 y );
XP_Bool dragDropContinue( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool dragDropEnd( BoardCtxt* board, XP_U16 x, XP_U16 y, XP_Bool* dragged );
XP_U16 xx, XP_U16 yy );
XP_Bool dragDropContinue( BoardCtxt* board, XP_U16 xx, XP_U16 yy );
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 dragDropIsBeingDragged( const BoardCtxt* board, XP_U16 col, XP_U16 row,
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,
XP_U16* addedIndx );
XP_Bool dragDropGetHintLimits( const BoardCtxt* board, BdHintLimits* limits );
XP_Bool dragDropIsDividerDrag( const BoardCtxt* board );
void dragDropTileInfo( const BoardCtxt* board, Tile* tile, XP_Bool* isBlank );