mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-28 09:58:30 +01:00
fold hint-region-drag into dragdrpp, saving a bunch of code and
gaining scrolling during drag on small screens.
This commit is contained in:
parent
5c8756856d
commit
d00aa75a12
4 changed files with 274 additions and 265 deletions
|
@ -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 */
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in a new issue