When internal focus reaches edge of object, move it back up and onto

the next object using a callback to the platform to determine what, if
any, object is next.  Adjust curses platform to cooperate.  Works
well.  Palm is next.
This commit is contained in:
ehouse 2006-11-07 05:46:44 +00:00
parent 005fd92fd4
commit 9a00908cdb
5 changed files with 127 additions and 113 deletions

View file

@ -1,4 +1,4 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
E/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2002 by Eric House (xwords@eehouse.org). All rights reserved.
*
@ -113,8 +113,7 @@ static XP_Bool advanceArrow( BoardCtxt* board );
#ifdef KEY_SUPPORT
static XP_Bool getArrow( BoardCtxt* board, XP_U16* col, XP_U16* row );
static XP_Bool board_moveArrow( BoardCtxt* board, XP_Key cursorKey,
XP_Bool canCycle );
static XP_Bool board_moveArrow( BoardCtxt* board, XP_Key cursorKey );
static XP_Bool setArrowVisibleFor( BoardCtxt* board, XP_U16 player,
XP_Bool visible );
@ -1921,6 +1920,9 @@ invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
{
board->redrawFlags[row] |= 1 << col;
XP_ASSERT( col < MAX_ROWS );
XP_ASSERT( row < MAX_ROWS );
/* if the trade window is up and this cell intersects it, set up to draw
it again */
if ( (board->trayVisState != TRAY_HIDDEN) && TRADE_IN_PROGRESS(board) ) {
@ -1936,29 +1938,6 @@ invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row )
board->needsDrawing = XP_TRUE;
} /* invalCell */
#ifdef KEYBOARD_NAV
static XP_Bool
focusNext( BoardCtxt* board )
{
BoardObjectType typ;
switch ( board->focussed ) {
case OBJ_SCORE:
typ = OBJ_BOARD;
break;
case OBJ_BOARD:
typ = OBJ_TRAY;
break;
case OBJ_TRAY:
case OBJ_NONE:
typ = OBJ_SCORE;
break;
}
board->focussed = typ;
return XP_TRUE;
} /* focusNext */
#endif
#ifdef POINTER_SUPPORT
static XP_Bool
pointOnSomething( BoardCtxt* board, XP_U16 x, XP_U16 y, BoardObjectType* wp )
@ -2738,6 +2717,10 @@ board_handleKey( BoardCtxt* board, XP_Key key )
} else if ( board->focussed == OBJ_TRAY ) {
result = tray_moveCursor( board, key );
}
} else {
invalFocusOwner( board );
shiftFocusUp( board, key );
result = XP_TRUE;
}
break;
#endif
@ -2751,12 +2734,7 @@ board_handleKey( BoardCtxt* board, XP_Key key )
#ifdef KEYBOARD_NAV
case XP_FOCUSCHANGE_KEY:
invalFocusOwner( board );
if ( board->focusHasDived ) {
board->focusHasDived = XP_FALSE; /* come back up */
} else if ( focusNext( board ) ) {
invalFocusOwner( board );
}
shiftFocusUp( board, XP_CURSOR_KEY_RIGHT );
result = XP_TRUE;
break;
@ -2868,7 +2846,8 @@ board_focusChanged( BoardCtxt* board, BoardObjectType typ, XP_Bool gained )
draw = invalFocusOwner( board ) || draw;
}
board->focussed = typ;
XP_LOGF( "%s: set focussed to %d", __FUNCTION__, (int)typ );
XP_LOGF( "%s: set focussed to %s", __FUNCTION__,
BoardObjectType_2str(typ) );
draw = invalFocusOwner( board ) || draw;
board->focusHasDived = XP_FALSE;
} else {
@ -2897,12 +2876,27 @@ board_toggle_arrowDir( BoardCtxt* board )
}
} /* board_toggle_cursorDir */
void
shiftFocusUp( BoardCtxt* board, XP_Key key )
{
BoardObjectType next = OBJ_NONE;
util_notifyFocusChange( board->util, board->focussed, key, &next );
if ( board->focussed != next ) {
(void)board_focusChanged( board, board->focussed, XP_FALSE );
board->focusHasDived = XP_FALSE;
(void)board_focusChanged( board, next, XP_TRUE );
}
}
static XP_Bool
moveScoreCursor( BoardCtxt* board, XP_Key key )
{
XP_Bool result = XP_TRUE;
XP_U16 nPlayers = board->gi->nPlayers;
XP_U16 scoreCursorLoc = board->scoreCursorLoc + nPlayers;
XP_S16 scoreCursorLoc = board->scoreCursorLoc;
switch ( key ) {
case XP_CURSOR_KEY_DOWN:
@ -2916,7 +2910,11 @@ moveScoreCursor( BoardCtxt* board, XP_Key key )
default:
result = XP_FALSE;
}
board->scoreCursorLoc = scoreCursorLoc % nPlayers;
if ( scoreCursorLoc < 0 || scoreCursorLoc >= nPlayers ) {
shiftFocusUp( board, key );
} else {
board->scoreCursorLoc = scoreCursorLoc;
}
board->scoreBoardInvalid = XP_TRUE;
return result;
@ -2931,17 +2929,16 @@ advanceArrow( BoardCtxt* board )
XP_ASSERT( board->trayVisState == TRAY_REVEALED );
return board_moveArrow( board, key, XP_FALSE );
return board_moveArrow( board, key );
} /* advanceArrow */
static XP_Bool
figureNextLoc( BoardCtxt* board, XP_Key cursorKey, XP_Bool canCycle,
figureNextLoc( BoardCtxt* board, XP_Key cursorKey, XP_Bool canShiftFocus,
XP_Bool avoidOccupied, XP_U16* colP, XP_U16* rowP )
{
XP_S16 max;
XP_S16* useWhat;
XP_S16 end = 0;
XP_U16 counter = 0;
XP_S16 incr = 0;
XP_U16 numCols, numRows;
XP_Bool result = XP_FALSE;
@ -2958,25 +2955,25 @@ figureNextLoc( BoardCtxt* board, XP_Key cursorKey, XP_Bool canCycle,
case XP_CURSOR_KEY_DOWN:
incr = 1;
useWhat = (XP_S16*)rowP;
max = numRows;
max = numRows - 1;
end = max;
break;
case XP_CURSOR_KEY_UP:
incr = -1;
useWhat = (XP_S16*)rowP;
max = numRows;
end = -1;
max = numRows - 1;
end = 0;
break;
case XP_CURSOR_KEY_LEFT:
incr = -1;
useWhat = (XP_S16*)colP;
max = numCols;
end = -1;
max = numCols - 1;
end = 0;
break;
case XP_CURSOR_KEY_RIGHT:
incr = 1;
useWhat = (XP_S16*)colP;
max = numCols;
max = numCols - 1;
end = max;
break;
default:
@ -2985,19 +2982,18 @@ figureNextLoc( BoardCtxt* board, XP_Key cursorKey, XP_Bool canCycle,
XP_ASSERT( incr != 0 );
for ( counter = max; ; --counter ) {
*useWhat += incr;
if ( (counter == 0) || (!canCycle && (*useWhat == end)) ) {
for ( ; ; ) {
if ( *useWhat == end ) {
if ( canShiftFocus ) {
shiftFocusUp( board, cursorKey );
result = XP_TRUE;
}
break;
}
*useWhat = (*useWhat + max) % max;
result = XP_TRUE;
*useWhat += incr;
if ( !avoidOccupied
|| !cellOccupied( board, *colP, *rowP, XP_TRUE ) ) {
result = XP_TRUE;
|| !cellOccupied( board, *colP, *rowP, XP_TRUE ) ) {
break;
}
}
@ -3007,14 +3003,14 @@ figureNextLoc( BoardCtxt* board, XP_Key cursorKey, XP_Bool canCycle,
} /* figureNextLoc */
static XP_Bool
board_moveArrow( BoardCtxt* board, XP_Key cursorKey, XP_Bool canCycle )
board_moveArrow( BoardCtxt* board, XP_Key cursorKey )
{
XP_U16 col, row;
XP_Bool changed;
setArrowVisible( board, XP_TRUE );
(void)getArrow( board, &col, &row );
changed = figureNextLoc( board, cursorKey, canCycle, XP_TRUE, &col, &row );
changed = figureNextLoc( board, cursorKey, XP_FALSE, XP_TRUE, &col, &row );
if ( changed ) {
(void)setArrow( board, col, row );
}

View file

@ -199,6 +199,7 @@ XP_Bool rectsIntersect( XP_Rect* rect1, XP_Rect* rect2 );
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey );
XP_Bool tray_keyAction( BoardCtxt* board );
DrawFocusState dfsFor( BoardCtxt* board, BoardObjectType obj );
void shiftFocusUp( BoardCtxt* board, XP_Key key );
#else
# define dfsFor( board, obj ) DFS_NONE
#endif

View file

@ -617,33 +617,26 @@ tray_moveCursor( BoardCtxt* board, XP_Key cursorKey )
{
XP_Bool result;
XP_U16 selPlayer = board->selPlayer;
XP_U16 numTrayTiles = model_getNumTilesInTray( board->model,
selPlayer );
XP_U16 pos;
TileBit newSel;
TileBit oldSel = 1 << board->trayCursorLoc[selPlayer];
numTrayTiles = MAX_TRAY_TILES;
if ( cursorKey == XP_CURSOR_KEY_UP ) {
result = board_moveDivider( board, XP_FALSE );
} else if ( cursorKey == XP_CURSOR_KEY_DOWN ) {
result = board_moveDivider( board, XP_TRUE );
} else {
pos = indexForBits( oldSel );
XP_S16 pos;
pos += numTrayTiles; /* add what we'll mod by below: makes circular */
if ( cursorKey == XP_CURSOR_KEY_LEFT ) {
--pos;
} else if ( cursorKey == XP_CURSOR_KEY_RIGHT ) {
++pos;
board_invalTrayTiles( board, 1 << board->trayCursorLoc[selPlayer] );
pos = board->trayCursorLoc[selPlayer];
pos += cursorKey == XP_CURSOR_KEY_RIGHT ? 1 : -1;
if ( pos < 0 || pos >= MAX_TRAY_TILES ) {
shiftFocusUp( board, cursorKey );
} else {
board->trayCursorLoc[selPlayer] = pos;
board_invalTrayTiles( board, 1 << pos );
}
pos %= numTrayTiles;
board->trayCursorLoc[selPlayer] = pos;
newSel = 1 << pos;
board_invalTrayTiles( board, newSel | oldSel );
board_invalTrayTiles( board, 1 << board->trayCursorLoc[selPlayer] );
result = XP_TRUE;
}

View file

@ -155,6 +155,11 @@ typedef struct UtilVtable {
void (*m_util_engineStarting)( XW_UtilCtxt* uc, XP_U16 nBlanks );
void (*m_util_engineStopping)( XW_UtilCtxt* uc );
#endif
#ifdef KEYBOARD_NAV
void (*m_util_notifyFocusChange)( XW_UtilCtxt* uc, BoardObjectType cur,
XP_Key key, BoardObjectType* next );
#endif
} UtilVtable;
@ -241,4 +246,8 @@ struct XW_UtilCtxt {
# define util_engineStopping( uc )
# endif
# ifdef KEYBOARD_NAV
# define util_notifyFocusChange( uc, c, k, n ) \
(uc)->vtable->m_util_notifyFocusChange((uc),(c),(k),(n))
# endif
#endif

View file

@ -1,4 +1,4 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2000 by Eric House (xwords@eehouse.org). All rights reserved.
*
@ -53,13 +53,20 @@
#include "server.h"
#include "memstream.h"
#include "util.h"
#include "dbgutil.h"
#define MENU_WINDOW_HEIGHT 5 /* three lines plus borders */
#define INFINITE_TIMEOUT -1
CursesAppGlobals globals; /* must be global b/c of SIGWINCH_handler */
static void changeFocus( CursesAppGlobals* globals );
static void changeMenuForFocus( CursesAppGlobals* globals,
BoardObjectType obj );
static XP_Bool handleLeft( CursesAppGlobals* globals );
static XP_Bool handleRight( CursesAppGlobals* globals );
static XP_Bool handleUp( CursesAppGlobals* globals );
static XP_Bool handleDown( CursesAppGlobals* globals );
#ifdef MEM_DEBUG
# define MEMPOOL params->util->mpool,
@ -220,6 +227,30 @@ curses_util_engineProgressCallback( XW_UtilCtxt* XP_UNUSED(uc) )
return XP_TRUE;
} /* curses_util_engineProgressCallback */
static void
curses_util_notifyFocusChange( XW_UtilCtxt* uc, BoardObjectType cur,
XP_Key key, BoardObjectType* nextP )
{
BoardObjectType nxt;
CursesAppGlobals* globals;
XP_LOGF( "%s(%s)", __FUNCTION__, BoardObjectType_2str(cur) );
XP_Bool forward = key == XP_CURSOR_KEY_DOWN
|| key == XP_CURSOR_KEY_RIGHT;
switch( cur ) {
case OBJ_SCORE: nxt = forward? OBJ_TRAY : OBJ_BOARD; break;
case OBJ_BOARD: nxt = forward? OBJ_SCORE : OBJ_TRAY; break;
case OBJ_TRAY: nxt = forward? OBJ_BOARD : OBJ_SCORE; break;
case OBJ_NONE: nxt = OBJ_BOARD;
}
globals = (CursesAppGlobals*)uc->closure;
changeMenuForFocus( globals, nxt );
*nextP = nxt;
XP_LOGF( "%s()=>%s", __FUNCTION__, BoardObjectType_2str(*nextP) );
}
#ifdef XWFEATURE_RELAY
static void
curses_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why, XP_U16 when,
@ -322,7 +353,6 @@ handleTab( CursesAppGlobals* globals )
{
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
XP_FOCUSCHANGE_KEY );
changeFocus( globals );
return XP_TRUE;
} /* handleTab */
@ -416,6 +446,14 @@ MenuList sharedMenuList[] = {
{ handleTab, "Change focus", "<tab>", '\t' },
{ handleRet, "Click/tap", "<ret>", '\r' },
{ handleHint, "Hint", "?", '?' },
#ifdef KEYBOARD_NAV
{ handleLeft, "Left", "H", 'H' },
{ handleRight, "Right", "L", 'L' },
{ handleUp, "Up", "J", 'J' },
{ handleDown, "Down", "K", 'K' },
#endif
{ handleCommit, "Commit move", "C", 'C' },
{ handleFlip, "Flip", "F", 'F' },
{ handleToggleValues, "Show values", "V", 'V' },
@ -436,22 +474,6 @@ handleLeft( CursesAppGlobals* globals )
return XP_TRUE;
} /* handleLeft */
static XP_Bool
handleDivLeft( CursesAppGlobals* globals )
{
globals->doDraw = board_moveDivider( globals->cGlobals.game.board,
XP_FALSE );
return XP_TRUE;
} /* handleDivLeft */
static XP_Bool
handleDivRight( CursesAppGlobals* globals )
{
globals->doDraw = board_moveDivider( globals->cGlobals.game.board,
XP_TRUE );
return XP_TRUE;
} /* handleDivRight */
static XP_Bool
handleRight( CursesAppGlobals* globals )
{
@ -478,31 +500,17 @@ handleDown( CursesAppGlobals* globals )
#endif
MenuList boardMenuList[] = {
#ifdef KEYBOARD_NAV
{ handleLeft, "Left", "H", 'H' },
{ handleRight, "Right", "L", 'L' },
{ handleUp, "Up", "J", 'J' },
{ handleDown, "Down", "K", 'K' },
#endif
{ NULL, NULL, NULL, '\0'}
};
MenuList scoreMenuList[] = {
#ifdef KEYBOARD_NAV
{ handleUp, "Up", "J", 'J' },
{ handleDown, "Down", "K", 'K' },
#endif
{ NULL, NULL, NULL, '\0'}
};
MenuList trayMenuList[] = {
#ifdef KEYBOARD_NAV
{ handleLeft, "Left", "H", 'H' },
{ handleRight, "Right", "L", 'L' },
{ handleDivLeft, "Div left", "{", '{' },
{ handleDivRight, "Div right", "}", '}' },
#endif
{ handleJuggle, "Juggle", "J", 'J' },
{ handleJuggle, "Juggle", "G", 'G' },
{ handleHide, "[un]hIde", "I", 'I' },
{ NULL, NULL, NULL, '\0'}
@ -556,6 +564,9 @@ drawMenuFromList( CursesAppGlobals* globals, MenuList* menuList )
if ( !isShared ) {
done = XP_TRUE;
break;
} else if ( menuList->handler == NULL ) {
done = XP_TRUE;
break;
} else {
isShared = XP_FALSE;
entry = menuList;
@ -563,6 +574,7 @@ drawMenuFromList( CursesAppGlobals* globals, MenuList* menuList )
}
}
XP_ASSERT( nLines > 0 );
if ( line % nLines == 0 ) {
line = 0;
col += maxKey + maxCmd + 2;
@ -802,11 +814,9 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch )
} /* blocking_gotEvent */
static void
changeFocus( CursesAppGlobals* globals )
changeMenuForFocus( CursesAppGlobals* globals, BoardObjectType focussed )
{
#ifdef KEYBOARD_NAV
BoardObjectType focussed =
board_getFocusOwner( globals->cGlobals.game.board );
if ( focussed == OBJ_TRAY ) {
globals->menuList = trayMenuList;
drawMenuFromList( globals, trayMenuList );
@ -820,7 +830,7 @@ changeFocus( CursesAppGlobals* globals )
XP_ASSERT(0);
}
#endif
} /* changeFocus */
} /* changeMenuForFocus */
#if 0
static void
@ -916,7 +926,12 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_notifyGameOver = curses_util_notifyGameOver;
util->vtable->m_util_hiliteCell = curses_util_hiliteCell;
util->vtable->m_util_engineProgressCallback =
curses_util_engineProgressCallback;
curses_util_engineProgressCallback;
#ifdef KEYBOARD_NAV
util->vtable->m_util_notifyFocusChange = curses_util_notifyFocusChange;
#endif
#ifdef XWFEATURE_RELAY
util->vtable->m_util_setTimer = curses_util_setTimer;
#endif