Two big changes. Pass focus bit into all or and players when focus

not dived and tray or scoreboard focussed.  This lets platform decide
to display top-level focus via mods to all elements.  Second, when
moving focus to top level from dived, claim not to have handled the
key event (but return true if needs redraw).  This allows platform to
handle shifting focus without requiring callback (which removed.)
This commit is contained in:
ehouse 2006-11-14 06:46:04 +00:00
parent 9aa3759761
commit 0d013a0599
7 changed files with 115 additions and 101 deletions

View file

@ -1,6 +1,7 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 1997 - 2002 by Eric House (xwords@eehouse.org). All rights reserved.
* Copyright 1997 - 2006 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -121,7 +122,8 @@ static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey,
#endif
#ifdef KEYBOARD_NAV
static XP_Bool board_moveCursor( BoardCtxt* board, XP_Key cursorKey );
static XP_Bool board_moveCursor( BoardCtxt* board, XP_Key cursorKey,
XP_Bool* up );
static XP_Bool invalFocusOwner( BoardCtxt* board );
#endif
#ifdef XWFEATURE_SEARCHLIMIT
@ -2486,30 +2488,32 @@ board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y )
#endif /* #ifdef POINTER_SUPPORT */
#ifdef KEYBOARD_NAV
static XP_Key
flipKey( BoardCtxt* board, XP_Key key ) {
if ( board->isFlipped ) {
XP_Key
flipKey( XP_Key key, XP_Bool flip ) {
XP_Key result = key;
if ( flip ) {
switch( key ) {
case XP_CURSOR_KEY_DOWN:
return XP_CURSOR_KEY_RIGHT;
result = XP_CURSOR_KEY_RIGHT; break;
case XP_CURSOR_KEY_UP:
return XP_CURSOR_KEY_LEFT;
result = XP_CURSOR_KEY_LEFT; break;
case XP_CURSOR_KEY_LEFT:
return XP_CURSOR_KEY_UP;
result = XP_CURSOR_KEY_UP; break;
case XP_CURSOR_KEY_RIGHT:
return XP_CURSOR_KEY_DOWN;
result = XP_CURSOR_KEY_DOWN; break;
default:
XP_ASSERT(0);
}
}
return key;
return result;
} /* flipKey */
#endif
XP_Bool
board_handleKey( BoardCtxt* board, XP_Key key )
board_handleKey( BoardCtxt* board, XP_Key key, XP_Bool* pHandled )
{
XP_Bool result = XP_FALSE;
XP_Bool redraw = XP_FALSE;
XP_Bool handled = XP_FALSE;
XP_Bool trayVisible = board->trayVisState == TRAY_REVEALED;
XP_Bool gotArrow;
@ -2520,25 +2524,33 @@ board_handleKey( BoardCtxt* board, XP_Key key )
case XP_CURSOR_KEY_LEFT:
case XP_CURSOR_KEY_RIGHT:
if ( board->focusHasDived ) {
XP_Bool up = XP_FALSE;
if ( board->focussed == OBJ_BOARD ) {
result = board_moveCursor( board, flipKey( board, key ) );
redraw = board_moveCursor( board,
flipKey( key, board->isFlipped ),
&up );
} else if ( board->focussed == OBJ_SCORE ) {
result = moveScoreCursor( board, key );
redraw = moveScoreCursor( board, key, &up );
} else if ( board->focussed == OBJ_TRAY ) {
result = tray_moveCursor( board, key );
redraw = tray_moveCursor( board, key, &up );
}
} else if ( board->focussed != OBJ_NONE ) {
invalFocusOwner( board );
shiftFocusUp( board, key );
result = XP_TRUE;
if ( up ) {
invalFocusOwner( board );
board->focusHasDived = XP_FALSE;
invalFocusOwner( board );
} else {
handled = XP_TRUE;
}
} else {
/* Do nothing. We don't handle transition among top-level
focussed objects. Platform must. */
}
break;
#endif
case XP_CURSOR_KEY_DEL:
if ( trayVisible ) {
replaceLastTile( board );
result = XP_TRUE;
handled = redraw = replaceLastTile( board );
}
break;
@ -2548,35 +2560,37 @@ board_handleKey( BoardCtxt* board, XP_Key key )
invalFocusOwner( board );
board->focusHasDived = XP_FALSE;
invalFocusOwner( board );
result = XP_TRUE;
handled = redraw = XP_TRUE;
}
break;
case XP_RETURN_KEY:
if ( board->focusHasDived ) {
result = XP_TRUE; /* even if don't draw, we handle it!! */
handled = XP_TRUE; /* even if don't draw, we handle it!! */
if ( board->focussed == OBJ_TRAY ) {
if ( trayVisible ) {
(void)tray_keyAction( board );
redraw = tray_keyAction( board );
} else {
(void)askRevealTray( board );
redraw = askRevealTray( board );
}
} else if ( board->focussed == OBJ_BOARD ) {
/* mimic pen-down/pen-up on cursor */
if ( trayVisible ) {
BdCursorLoc loc = board->bdCursor[board->selPlayer];
(void)handleActionInCell( board, loc.col, loc.row );
redraw = handleActionInCell( board, loc.col, loc.row );
} else {
askRevealTray( board );
redraw = askRevealTray( board );
}
} else if ( board->focussed == OBJ_SCORE ) {
/* tap on what's already selected: reveal tray, etc. */
board_selectPlayer( board, board->scoreCursorLoc );
redraw = XP_TRUE; /* must assume */
}
} else if ( board->focussed != OBJ_NONE ) {
redraw = invalFocusOwner( board );
board->focusHasDived = XP_TRUE;
board_invalAll( board ); /* just want to inval borders! */
result = XP_TRUE;
redraw = invalFocusOwner( board );
handled = XP_TRUE;
}
break;
#endif
@ -2584,14 +2598,18 @@ board_handleKey( BoardCtxt* board, XP_Key key )
default:
XP_ASSERT( key >= XP_KEY_LAST );
result = trayVisible && moveKeyTileToBoard( board, key, &gotArrow );
handled = redraw = trayVisible
&& moveKeyTileToBoard( board, key, &gotArrow );
if ( result && gotArrow && !advanceArrow( board ) ) {
if ( handled && gotArrow && !advanceArrow( board ) ) {
setArrowVisible( board, XP_FALSE );
}
} /* switch */
return result;
if ( !!pHandled ) {
*pHandled = handled;
}
return redraw;
} /* board_handleKey */
#ifdef KEYBOARD_NAV
@ -2690,21 +2708,6 @@ board_toggle_arrowDir( BoardCtxt* board )
}
} /* board_toggle_cursorDir */
void
shiftFocusUp( BoardCtxt* board, XP_Key key )
{
BoardObjectType next = OBJ_NONE;
XP_ASSERT( board->focussed != 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 );
}
}
#endif /* KEYBOARD_NAV */
static XP_Bool
@ -2720,8 +2723,8 @@ advanceArrow( BoardCtxt* board )
static XP_Bool
figureNextLoc( BoardCtxt* board, XP_Key cursorKey,
XP_Bool XP_UNUSED_KEYBOARD_NAV(canShiftFocus),
XP_Bool inclPending, XP_U16* colP, XP_U16* rowP )
XP_Bool inclPending, XP_U16* colP, XP_U16* rowP,
XP_Bool* pUp )
{
XP_S16 max;
XP_S16* useWhat;
@ -2772,9 +2775,8 @@ figureNextLoc( BoardCtxt* board, XP_Key cursorKey,
for ( ; ; ) {
if ( *useWhat == end ) {
#ifdef KEYBOARD_NAV
if ( canShiftFocus ) {
shiftFocusUp( board, cursorKey );
result = XP_TRUE;
if ( !!pUp ) {
*pUp = XP_TRUE;
}
#endif
break;
@ -2798,7 +2800,7 @@ board_moveArrow( BoardCtxt* board, XP_Key cursorKey )
setArrowVisible( board, XP_TRUE );
(void)getArrow( board, &col, &row );
changed = figureNextLoc( board, cursorKey, XP_FALSE, XP_TRUE, &col, &row );
changed = figureNextLoc( board, cursorKey, XP_TRUE, &col, &row, NULL );
if ( changed ) {
(void)setArrow( board, col, row );
}
@ -2807,15 +2809,14 @@ board_moveArrow( BoardCtxt* board, XP_Key cursorKey )
#ifdef KEYBOARD_NAV
static XP_Bool
board_moveCursor( BoardCtxt* board, XP_Key cursorKey )
board_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool* up )
{
BdCursorLoc loc = board->bdCursor[board->selPlayer];
XP_U16 col = loc.col;
XP_U16 row = loc.row;
XP_Bool changed;
changed = figureNextLoc( board, cursorKey, XP_TRUE, XP_FALSE,
&col, &row );
changed = figureNextLoc( board, cursorKey, XP_FALSE, &col, &row, up );
if ( changed ) {
invalCell( board, loc.col, loc.row );
invalCell( board, col, row );

View file

@ -121,7 +121,7 @@ XP_Bool board_handlePenMove( BoardCtxt* board, XP_U16 x, XP_U16 y );
XP_Bool board_handlePenUp( BoardCtxt* board, XP_U16 x, XP_U16 y );
#endif
XP_Bool board_handleKey( BoardCtxt* board, XP_Key key );
XP_Bool board_handleKey( BoardCtxt* board, XP_Key key, XP_Bool* handled );
#ifdef KEYBOARD_NAV
/* void board_focusChange( BoardCtxt* board ); */

View file

@ -198,7 +198,8 @@ XP_Bool rectsIntersect( XP_Rect* rect1, XP_Rect* rect2 );
void board_selectPlayer( BoardCtxt* board, XP_U16 newPlayer );
#ifdef KEYBOARD_NAV
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey );
XP_Key flipKey( XP_Key key, XP_Bool flip );
XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool* up );
XP_Bool tray_keyAction( BoardCtxt* board );
DrawFocusState dfsFor( BoardCtxt* board, BoardObjectType obj );
void shiftFocusUp( BoardCtxt* board, XP_Key key );

View file

@ -74,12 +74,6 @@ drawScoreBoard( BoardCtxt* board )
cursorIndex = board->scoreCursorLoc;
}
}
/* XP_Bool focusAll = (board->focussed == OBJ_SCORE) */
/* && !board->focusHasDived; */
/* XP_S16 cursorIndex = ( (board->focussed == OBJ_SCORE) */
/* && board->focusHasDived ) ? */
/* board->scoreCursorLoc : -1; */
#endif
draw_scoreBegin( board->draw, &board->scoreBdBounds, nPlayers,
dfsFor( board, OBJ_SCORE ) );
@ -285,30 +279,40 @@ handlePenUpScore( BoardCtxt* board, XP_U16 x, XP_U16 y )
#ifdef KEYBOARD_NAV
XP_Bool
moveScoreCursor( BoardCtxt* board, XP_Key key )
moveScoreCursor( BoardCtxt* board, XP_Key key, XP_Bool* pUp )
{
XP_Bool result = XP_TRUE;
XP_U16 nPlayers = board->gi->nPlayers;
XP_S16 scoreCursorLoc = board->scoreCursorLoc;
XP_Bool up = XP_FALSE;
/* Depending on scoreboard layout, keys move cursor or leave. */
key = flipKey( key, board->scoreSplitHor );
switch ( key ) {
case XP_CURSOR_KEY_DOWN:
case XP_CURSOR_KEY_RIGHT:
++scoreCursorLoc;
break;
case XP_CURSOR_KEY_RIGHT:
up = XP_TRUE;
break;
case XP_CURSOR_KEY_UP:
case XP_CURSOR_KEY_LEFT:
--scoreCursorLoc;
break;
case XP_CURSOR_KEY_LEFT:
up = XP_TRUE;
break;
default:
result = XP_FALSE;
}
if ( scoreCursorLoc < 0 || scoreCursorLoc >= nPlayers ) {
shiftFocusUp( board, key );
if ( !up && ((scoreCursorLoc < 0) || (scoreCursorLoc >= nPlayers)) ) {
up = XP_TRUE;
} else {
board->scoreCursorLoc = scoreCursorLoc;
board->scoreBoardInvalid = XP_TRUE;
}
board->scoreBoardInvalid = XP_TRUE;
*pUp = up;
return result;
} /* moveScoreCursor */

View file

@ -31,7 +31,7 @@ XP_Bool handlePenUpScore( BoardCtxt* board, XP_U16 x, XP_U16 y );
#endif
#ifdef KEYBOARD_NAV
XP_Bool moveScoreCursor( BoardCtxt* board, XP_Key key );
XP_Bool moveScoreCursor( BoardCtxt* board, XP_Key key, XP_Bool* up );
#endif
#endif

View file

@ -111,12 +111,13 @@ drawTray( BoardCtxt* board )
if ( draw_trayBegin( board->draw, &board->trayBounds, turn,
dfsFor( board, OBJ_TRAY ) ) ) {
DictionaryCtxt* dictionary = model_getDictionary( board->model );
XP_S16 cursorIndex = -1;
XP_S16 cursorBits = 0;
#ifdef KEYBOARD_NAV
if ( board->focusHasDived && board->focussed == OBJ_TRAY ) {
TileBit cursorLoc = 1 << board->trayCursorLoc[turn];
if ( !!cursorLoc ) {
cursorIndex = indexForBits( cursorLoc );
if ( board->focussed == OBJ_TRAY ) {
if ( board->focusHasDived ) {
cursorBits = 1 << board->trayCursorLoc[turn];
} else {
cursorBits = ALLTILES;
}
}
#endif
@ -139,12 +140,13 @@ drawTray( BoardCtxt* board )
erasing */
for ( i = MAX_TRAY_TILES - 1; i >= 0; --i ) {
CellFlags flags = CELL_NONE;
XP_U16 mask = 1 << i;
if ( (board->trayInvalBits & (1 << i)) == 0 ) {
if ( (board->trayInvalBits & mask) == 0 ) {
continue;
}
#ifdef KEYBOARD_NAV
if ( cursorIndex == i ) {
if ( (cursorBits & mask) != 0 ) {
flags |= CELL_ISCURSOR;
}
#endif
@ -200,11 +202,13 @@ drawTray( BoardCtxt* board )
board->dividerInvalid = XP_FALSE;
}
drawPendingScore( board, cursorIndex == MAX_TRAY_TILES - 1 );
drawPendingScore( board,
(cursorBits & (1<<(MAX_TRAY_TILES-1))) != 0 );
#ifdef KEYBOARD_NAV
if ( cursorIndex >= 0 ) {
figureTrayTileRect( board, cursorIndex, &tileRect );
if ( (cursorBits != 0) && (cursorBits != ALLTILES) ) {
figureTrayTileRect( board, indexForBits(cursorBits),
&tileRect );
draw_drawCursor( board->draw, OBJ_TRAY, &tileRect );
}
#endif
@ -634,32 +638,40 @@ board_juggleTray( BoardCtxt* board )
#ifdef KEYBOARD_NAV
XP_Bool
tray_moveCursor( BoardCtxt* board, XP_Key cursorKey )
tray_moveCursor( BoardCtxt* board, XP_Key cursorKey, XP_Bool* up )
{
XP_Bool result;
XP_U16 selPlayer = board->selPlayer;
XP_S16 pos;
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 {
XP_S16 pos;
switch (cursorKey ) {
case XP_CURSOR_KEY_UP:
case XP_CURSOR_KEY_DOWN:
*up = XP_TRUE;
/* moving the divider needs to be hard to do accidentally since it
confuses users when juggle and hint stop working. But all things
must be possible via keyboard on devices that don't have
touchscreens. Probably need a new keytype XP_CURSOR_KEY_ALTDOWN
etc. */
/* result = board_moveDivider( board, XP_FALSE ); */
/* result = board_moveDivider( board, XP_TRUE ); */
break;
case XP_CURSOR_KEY_RIGHT:
case XP_CURSOR_KEY_LEFT:
board_invalTrayTiles( board, 1 << board->trayCursorLoc[selPlayer] );
pos = board->trayCursorLoc[selPlayer];
/* Loop in order to skip all empty tile slots but one */
for ( ; ; ) {
pos += cursorKey == XP_CURSOR_KEY_RIGHT ? 1 : -1;
pos += (cursorKey == XP_CURSOR_KEY_RIGHT ? 1 : -1);
if ( pos < 0 || pos >= MAX_TRAY_TILES ) {
shiftFocusUp( board, cursorKey );
*up = XP_TRUE;
} else {
/* Revisit this when able to never draw the cursor in a place
this won't allow it, e.g. when the tiles move after a
hint*/
hint */
/* if ( board->trayVisState == TRAY_REVEALED ) { */
/* XP_U16 count = model_getNumTilesInTray( board->model, */
/* XP_U16 count = model_getNumTilesInTray( board->model, */
/* selPlayer ); */
/* if ( (pos > count) && (pos < MAX_TRAY_TILES-1) ) { */
/* continue; */
@ -672,6 +684,10 @@ tray_moveCursor( BoardCtxt* board, XP_Key cursorKey )
}
board_invalTrayTiles( board, 1 << board->trayCursorLoc[selPlayer] );
result = XP_TRUE;
break;
default:
XP_ASSERT(0);
break;
}
return result;

View file

@ -156,10 +156,6 @@ typedef struct UtilVtable {
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;
@ -246,8 +242,4 @@ 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