From 3153e2b8670741b348cb133f8bc045d3654e3042 Mon Sep 17 00:00:00 2001 From: ehouse Date: Fri, 3 Nov 2006 06:23:54 +0000 Subject: [PATCH] Lots of progress on one-handed navigation: add gadgets to stand in for board scoreboard and tray on palm; make center drill into the focussed object and spacebar come back up then move the focus among them. Integrate with other focussable objects on main form. Go from separate drawCursor routines to same for all three, with cursor only visible when focus is drilled down. On curses, add a hilite rect routine that can be called after text is laid down, and use for cursors. --- xwords4/common/board.c | 508 ++++++++++++++++++++++------------ xwords4/common/board.h | 17 +- xwords4/common/boardp.h | 7 +- xwords4/common/comtypes.h | 19 ++ xwords4/common/config.mk | 2 + xwords4/common/draw.h | 18 +- xwords4/common/tray.c | 12 +- xwords4/linux/cursesdraw.c | 96 ++++--- xwords4/linux/cursesmain.c | 2 +- xwords4/linux/cursesmain.h | 10 +- xwords4/linux/gtkdraw.c | 6 +- xwords4/palm/Makefile | 2 +- xwords4/palm/common.rcp.pre | 11 + xwords4/palm/palmdraw.c | 139 +++++++++- xwords4/palm/palmmain.c | 75 +++++ xwords4/palm/palmmain.h | 5 + xwords4/palm/xwords4defines.h | 9 + 17 files changed, 657 insertions(+), 281 deletions(-) diff --git a/xwords4/common/board.c b/xwords4/common/board.c index 4a95a564f..4b5e8c9e5 100644 --- a/xwords4/common/board.c +++ b/xwords4/common/board.c @@ -60,6 +60,7 @@ #include "LocalizedStrIncludes.h" #include "boardp.h" +#include "dbgutil.h" #define bEND 0x62454e44 @@ -76,11 +77,11 @@ static XP_Bool drawCell( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_Bool skipBlanks ); static void figureBoardRect( BoardCtxt* board ); +static void drawBoard( BoardCtxt* board ); static void drawTimer( BoardCtxt* board ); static void drawScoreBoard( BoardCtxt* board ); static void invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row ); -static void -invalCellsUnderRect( BoardCtxt* board, XP_Rect* rect ); +static void invalCellsUnderRect( BoardCtxt* board, XP_Rect* rect ); static XP_Bool moveTileToBoard( BoardCtxt* board, XP_U16 col, XP_U16 row, XP_U16 tileIndex, Tile blankFace ); @@ -123,6 +124,7 @@ static XP_Bool moveKeyTileToBoard( BoardCtxt* board, XP_Key cursorKey ); #ifdef KEYBOARD_NAV static XP_Bool moveScoreCursor( BoardCtxt* board, XP_Key key ); static XP_Bool board_moveCursor( BoardCtxt* board, XP_Key cursorKey ); +static XP_Bool invalFocusOwner( BoardCtxt* board ); #endif #ifdef XWFEATURE_SEARCHLIMIT static HintAtts figureHintAtts( BoardCtxt* board, XP_U16 col, XP_U16 row ); @@ -874,18 +876,25 @@ board_formatRemainingTiles( BoardCtxt* board, XWStreamCtxt* stream ) server_formatRemainingTiles( board->server, stream, curPlayer ); } /* board_formatRemainingTiles */ -void -board_invalAll( BoardCtxt* board ) +static void +board_invalAllTiles( BoardCtxt* board ) { XP_U16 lastRow = model_numRows( board->model ); while ( lastRow-- ) { board->redrawFlags[lastRow] = ~0; } + board->tradingMiniWindowInvalid = XP_TRUE; + board->needsDrawing = XP_TRUE; +} /* board_invalAllTiles */ + +void +board_invalAll( BoardCtxt* board ) +{ + board_invalAllTiles( board ); board_invalTrayTiles( board, ALLTILES ); board->dividerInvalid = XP_TRUE; - board->tradingMiniWindowInvalid = XP_TRUE; board->scoreBoardInvalid = XP_TRUE; } /* board_invalAll */ @@ -1037,97 +1046,101 @@ board_draw( BoardCtxt* board ) drawScoreBoard( board ); - drawTray( board, board->focussed==OBJ_TRAY ); + drawTray( board ); - if ( board->needsDrawing - && draw_boardBegin( board->draw, - model_getDictionary( board->model ), - &board->boardBounds, - board->focussed == OBJ_BOARD ) ) { - - XP_Bool allDrawn = XP_TRUE; - XP_S16 lastCol, i; - XP_S16 row; - ModelCtxt* model = board->model; - BlankQueue bq; - - scrollIfCan( board ); /* this must happen before we count blanks - since it invalidates squares */ - - model_listPlacedBlanks( model, board->selPlayer, - board->trayVisState == TRAY_REVEALED, &bq ); - invalBlanksWithNeighbors( board, &bq ); - - /* Don't try to optimize this using lastVisibleRow etc. If the - board is flipped, "lastVisibleRow" here is really col. - redrawFlags is at the model level, pre-flip. */ - for ( row = model_numRows(model) - 1; row >= 0; --row ) { - XP_U16 rowFlags = board->redrawFlags[row]; - if ( rowFlags != 0 ) { - XP_U16 colMask; - XP_U16 failedBits = 0; - lastCol = model_numCols( model ); - for ( colMask = 1<<(lastCol-1); lastCol--; colMask >>= 1 ) { - if ( (rowFlags & colMask) != 0 ) { - if ( !drawCell( board, lastCol, row, XP_TRUE )) { - failedBits |= colMask; - allDrawn = XP_FALSE; - } - } - } - board->redrawFlags[row] = failedBits; - } - } - - /* draw the blanks we skipped before */ - for ( i = 0; i < bq.nBlanks; ++i ) { - if ( !drawCell( board, bq.col[i], bq.row[i], XP_FALSE ) ) { - allDrawn = XP_FALSE; - } - } - - if ( board->trayVisState == TRAY_REVEALED ) { - XP_Rect cursorRect; - BoardArrow* arrow = &board->boardArrow[board->selPlayer]; - - if ( arrow->visible ) { - XP_U16 col = arrow->col; - XP_U16 row = arrow->row; - XP_Bool drawVertical = - (arrow->vert == XP_CURSOR_KEY_DOWN) ^ board->isFlipped; - if ( getCellRect( board, col, row, &cursorRect ) ) { - XWBonusType bonus; - HintAtts hintAtts; - bonus = util_getSquareBonus( board->util, model, - col, row ); - hintAtts = figureHintAtts( board, col, row ); - draw_drawBoardArrow( board->draw, &cursorRect, - bonus, drawVertical, hintAtts ); - } - } -#ifdef KEYBOARD_NAV - { - BdCursorLoc loc = board->bdCursor[board->selPlayer]; - if ( getCellRect( board, loc.col, loc.row, &cursorRect ) ) { - draw_drawBoardCursor( board->draw, &cursorRect ); - } - } -#endif - - } - - drawTradeWindowIf( board ); - - draw_boardFinished( board->draw ); - - board->needsDrawing = !allDrawn; - } - -/* drawTray( board, board->focussed==OBJ_TRAY ); */ + drawBoard( board ); } return !board->needsDrawing; } /* board_draw */ +static void +drawBoard( BoardCtxt* board ) +{ + if ( board->needsDrawing + && draw_boardBegin( board->draw, + model_getDictionary( board->model ), + &board->boardBounds, + dfsFor( board, OBJ_BOARD ) ) ) { + + XP_Bool allDrawn = XP_TRUE; + XP_S16 lastCol, i; + XP_S16 row; + ModelCtxt* model = board->model; + BlankQueue bq; + XP_Rect cursorRect; + + scrollIfCan( board ); /* this must happen before we count blanks + since it invalidates squares */ + + model_listPlacedBlanks( model, board->selPlayer, + board->trayVisState == TRAY_REVEALED, &bq ); + invalBlanksWithNeighbors( board, &bq ); + + /* Don't try to optimize this using lastVisibleRow etc. If the + board is flipped, "lastVisibleRow" here is really col. + redrawFlags is at the model level, pre-flip. */ + for ( row = model_numRows(model) - 1; row >= 0; --row ) { + XP_U16 rowFlags = board->redrawFlags[row]; + if ( rowFlags != 0 ) { + XP_U16 colMask; + XP_U16 failedBits = 0; + lastCol = model_numCols( model ); + for ( colMask = 1<<(lastCol-1); lastCol--; colMask >>= 1 ) { + if ( (rowFlags & colMask) != 0 ) { + if ( !drawCell( board, lastCol, row, XP_TRUE )) { + failedBits |= colMask; + allDrawn = XP_FALSE; + } + } + } + board->redrawFlags[row] = failedBits; + } + } + + /* draw the blanks we skipped before */ + for ( i = 0; i < bq.nBlanks; ++i ) { + if ( !drawCell( board, bq.col[i], bq.row[i], XP_FALSE ) ) { + allDrawn = XP_FALSE; + } + } + + if ( board->trayVisState == TRAY_REVEALED ) { + BoardArrow* arrow = &board->boardArrow[board->selPlayer]; + + if ( arrow->visible ) { + XP_U16 col = arrow->col; + XP_U16 row = arrow->row; + XP_Bool drawVertical = + (arrow->vert == XP_CURSOR_KEY_DOWN) ^ board->isFlipped; + if ( getCellRect( board, col, row, &cursorRect ) ) { + XWBonusType bonus; + HintAtts hintAtts; + bonus = util_getSquareBonus( board->util, model, + col, row ); + hintAtts = figureHintAtts( board, col, row ); + draw_drawBoardArrow( board->draw, &cursorRect, + bonus, drawVertical, hintAtts ); + } + } + } + +#ifdef KEYBOARD_NAV + if ( board->focussed == OBJ_BOARD && board->focusHasDived ) { + BdCursorLoc loc = board->bdCursor[board->selPlayer]; + if ( getCellRect( board, loc.col, loc.row, &cursorRect ) ){ + draw_drawCursor( board->draw, OBJ_BOARD, &cursorRect ); + } + } +#endif + + drawTradeWindowIf( board ); + + draw_boardFinished( board->draw ); + + board->needsDrawing = !allDrawn; + } +} /* drawBoard */ + static XP_S16 figureSecondsLeft( BoardCtxt* board ) { @@ -1185,9 +1198,12 @@ drawScoreBoard( BoardCtxt* board ) DrawScoreData datum[MAX_NUM_PLAYERS]; XP_S16 scores[MAX_NUM_PLAYERS]; XP_Bool isVertical = !board->scoreSplitHor; - - draw_scoreBegin( board->draw, &board->scoreBdBounds, nPlayers, - board->focussed==OBJ_SCORE ); +#ifdef KEYBOARD_NAV + XP_Rect cursorRect; + XP_Rect* cursorRectP = NULL; +#endif + draw_scoreBegin( board->draw, &board->scoreBdBounds, nPlayers, + dfsFor( board, OBJ_SCORE ) ); /* Let platform decide whether the rem: string should be given any space once there are no tiles left. On Palm that space is @@ -1277,9 +1293,23 @@ drawScoreBoard( BoardCtxt* board ) draw_score_drawPlayer( board->draw, &innerRect, &scoreRect, &dp->dsi ); +#ifdef KEYBOARD_NAV + if ( i == board->scoreCursorLoc + && board->focussed == OBJ_SCORE + && board->focusHasDived ) { + cursorRect = scoreRect; + cursorRectP = &cursorRect; + } +#endif *adjustPt += *adjustDim; } +#ifdef KEYBOARD_NAV + if ( !!cursorRectP ) { + draw_drawCursor( board->draw, OBJ_SCORE, cursorRectP ); + } +#endif + draw_scoreFinished( board->draw ); } @@ -1289,6 +1319,24 @@ drawScoreBoard( BoardCtxt* board ) drawTimer( board ); } /* drawScoreBoard */ +#ifdef KEYBOARD_NAV +DrawFocusState +dfsFor( BoardCtxt* board, BoardObjectType obj ) +{ + DrawFocusState dfs; + if ( board->focussed == obj ) { + if ( board->focusHasDived ) { + dfs = DFS_DIVED; + } else { + dfs = DFS_TOP; + } + } else { + dfs = DFS_NONE; + } + return dfs; +} /* dfsFor */ +#endif + void board_setTrayLoc( BoardCtxt* board, XP_U16 trayLeft, XP_U16 trayTop, XP_U16 trayWidth, XP_U16 trayHeight, @@ -1882,13 +1930,22 @@ invalCell( BoardCtxt* board, XP_U16 col, XP_U16 row ) static XP_Bool focusNext( BoardCtxt* board ) { - short numHolders = 3; /* board */ - short tmp = (short)board->focussed; /* avoid franklin casting crap */ + 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; + } - tmp %= numHolders; - board->focussed = (BoardObjectType)(tmp + 1); /* skip OBJ_NONE */ - - return numHolders > 1; + board->focussed = typ; + return XP_TRUE; } /* focusNext */ #endif @@ -2663,13 +2720,14 @@ board_handleKey( BoardCtxt* board, XP_Key key ) case XP_CURSOR_KEY_UP: case XP_CURSOR_KEY_LEFT: case XP_CURSOR_KEY_RIGHT: - if ( board->focussed == OBJ_BOARD ) { - result = trayVisible && board_moveCursor( board, - flipKey(board,key) ); - } else if ( board->focussed == OBJ_SCORE ) { - result = moveScoreCursor( board, key ); - } else if ( trayVisible && board->focussed == OBJ_TRAY ) { - result = tray_moveCursor( board, key ); + if ( board->focusHasDived ) { + if ( board->focussed == OBJ_BOARD ) { + result = board_moveCursor( board, flipKey( board, key ) ); + } else if ( board->focussed == OBJ_SCORE ) { + result = moveScoreCursor( board, key ); + } else if ( board->focussed == OBJ_TRAY ) { + result = tray_moveCursor( board, key ); + } } break; #endif @@ -2683,27 +2741,40 @@ board_handleKey( BoardCtxt* board, XP_Key key ) #ifdef KEYBOARD_NAV case XP_FOCUSCHANGE_KEY: - if ( focusNext( board ) ) { - board_invalAll( board ); /* really just want to inval borders! */ - result = XP_TRUE; + invalFocusOwner( board ); + if ( board->focusHasDived ) { + board->focusHasDived = XP_FALSE; /* come back up */ + } else if ( focusNext( board ) ) { + invalFocusOwner( board ); } + result = XP_TRUE; break; case XP_RETURN_KEY: - if ( board->focussed == OBJ_TRAY ) { - if ( trayVisible ) { - result = tray_keyAction( board ); - } else { - result = askRevealTray( board ); - } - } else if ( board->focussed == OBJ_BOARD ) { - /* mimic pen-down/pen-up on cursor */ - BdCursorLoc loc = board->bdCursor[board->selPlayer]; - result = handleActionInCell( board, loc.col, loc.row ); - } else if ( board->focussed == OBJ_SCORE ) { - /* tap on what's already selected: reveal tray, etc. */ - board_selectPlayer( board, board->selPlayer ); - result = XP_TRUE; + if ( board->focusHasDived ) { + result = XP_TRUE; /* even if don't draw, we handle it!! */ + if ( board->focussed == OBJ_TRAY ) { + if ( trayVisible ) { + (void)tray_keyAction( board ); + } else { + (void)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 ); + } else { + askRevealTray( board ); + } + } else if ( board->focussed == OBJ_SCORE ) { + /* tap on what's already selected: reveal tray, etc. */ + board_selectPlayer( board, board->scoreCursorLoc ); + } + } else if ( board->focussed != OBJ_NONE ) { + board->focusHasDived = XP_TRUE; + board_invalAll( board ); /* just want to inval borders! */ + result = XP_TRUE; } break; #endif @@ -2721,8 +2792,88 @@ board_handleKey( BoardCtxt* board, XP_Key key ) return result; } /* board_handleKey */ -/* used by curses version only! */ #ifdef KEYBOARD_NAV + +static XP_Bool +invalFocusOwner( BoardCtxt* board ) +{ + XP_Bool draw = XP_TRUE; + XP_S16 selPlayer = board->selPlayer; + switch( board->focussed ) { + case OBJ_SCORE: + board->scoreBoardInvalid = XP_TRUE; + break; + case OBJ_BOARD: + if ( board->focusHasDived ) { + BdCursorLoc loc = board->bdCursor[selPlayer]; + invalCell( board, loc.col, loc.row ); + } else { + board_invalAllTiles( board ); + } + break; + case OBJ_TRAY: + if ( board->focusHasDived ) { + XP_U16 loc = board->trayCursorLoc[selPlayer]; + board_invalTrayTiles( board, 1 << loc ); + } else { + board_invalTrayTiles( board, ALLTILES ); + board->dividerInvalid = XP_TRUE; + } + break; + default: /* for compiler */ + draw = XP_FALSE; + break; + } + board->needsDrawing = draw; + return draw; +} /* invalFocusOwner */ + +XP_Bool +board_focusChanged( BoardCtxt* board, BoardObjectType typ, XP_Bool gained ) +{ + XP_Bool draw = XP_FALSE; + LOG_FUNC(); + /* Called when there's been a decision to advance the focus to a new + object, or when an object will lose it. Need to update internal data + structures, but also to communicate to client draw code in a way that + doesn't assume how it's representing focus. + + Should pop focus to top on gaining it. Calling code should not be + seeing internal movement as focus events, but as key events we handle + + One rule: each object must draw focus indicator entirely within its own + space. No interdependencies. So handling updating of focus indication + within the tray drawing process, for example, is ok. + + Problem: on palm at least take and lost are inverted: you get a take on + the new object before a lose on the previous one. So we want to ignore + lost events *except* when it's a loss of something we have currently -- + meaning the focus is moving to soemthing we don't control (a + platform-specific object) + */ + + if ( gained ) { + /* Are we losing focus we currently have elsewhere? */ + if ( typ != board->focussed ) { + draw = invalFocusOwner( board ) || draw; + } + board->focussed = typ; + XP_LOGF( "%s: set focussed to %d", __FUNCTION__, (int)typ ); + draw = invalFocusOwner( board ) || draw; + board->focusHasDived = XP_FALSE; + } else { + /* we're losing it; inval and clear IFF we currently have same focus, + otherwise ignore */ + if ( typ == board->focussed ) { + draw = invalFocusOwner( board ) || draw; + board->focussed = OBJ_NONE; + } + } + + LOG_RETURNF( "%d", (int)draw ); + return draw; +} /* board_focusChanged */ + XP_Bool board_toggle_arrowDir( BoardCtxt* board ) { @@ -2741,24 +2892,26 @@ moveScoreCursor( BoardCtxt* board, XP_Key key ) { XP_Bool result = XP_TRUE; XP_U16 nPlayers = board->gi->nPlayers; - XP_U16 selPlayer = board->selPlayer + nPlayers; + XP_U16 scoreCursorLoc = board->scoreCursorLoc + nPlayers; switch ( key ) { case XP_CURSOR_KEY_DOWN: case XP_CURSOR_KEY_RIGHT: - ++selPlayer; + ++scoreCursorLoc; break; case XP_CURSOR_KEY_UP: case XP_CURSOR_KEY_LEFT: - --selPlayer; + --scoreCursorLoc; break; default: result = XP_FALSE; } - board_selectPlayer( board, selPlayer % nPlayers ); + board->scoreCursorLoc = scoreCursorLoc % nPlayers; + board->scoreBoardInvalid = XP_TRUE; + return result; } /* moveScoreCursor */ -#endif +#endif /* KEYBOARD_NAV */ static XP_Bool advanceArrow( BoardCtxt* board ) @@ -2785,61 +2938,58 @@ figureNextLoc( BoardCtxt* board, XP_Key cursorKey, XP_Bool canCycle, /* XP_ASSERT( board->focussed == OBJ_BOARD ); */ /* don't allow cursor's jumps to reveal hidden tiles */ - if ( board->trayVisState != TRAY_REVEALED || cursorKey == XP_KEY_NONE ) { - return XP_FALSE; - } + if ( cursorKey != XP_KEY_NONE ) { - numRows = model_numRows( board->model ); - numCols = model_numCols( board->model ); + numRows = model_numRows( board->model ); + numCols = model_numCols( board->model ); - switch ( cursorKey ) { + switch ( cursorKey ) { - case XP_CURSOR_KEY_DOWN: - incr = 1; - useWhat = (XP_S16*)rowP; - max = numRows; - end = max; - break; - case XP_CURSOR_KEY_UP: - incr = -1; - useWhat = (XP_S16*)rowP; - max = numRows; - end = -1; - break; - case XP_CURSOR_KEY_LEFT: - incr = -1; - useWhat = (XP_S16*)colP; - max = numCols; - end = -1; - break; - case XP_CURSOR_KEY_RIGHT: - incr = 1; - useWhat = (XP_S16*)colP; - max = numCols; - end = max; - break; - default: - XP_ASSERT( XP_FALSE ); - return XP_FALSE; - } - - XP_ASSERT( incr != 0 ); - - for ( counter = max; ; --counter ) { - - *useWhat += incr; - - if ( (counter == 0) || (!canCycle && (*useWhat == end)) ) { - result = XP_FALSE; + case XP_CURSOR_KEY_DOWN: + incr = 1; + useWhat = (XP_S16*)rowP; + max = numRows; + end = max; break; + case XP_CURSOR_KEY_UP: + incr = -1; + useWhat = (XP_S16*)rowP; + max = numRows; + end = -1; + break; + case XP_CURSOR_KEY_LEFT: + incr = -1; + useWhat = (XP_S16*)colP; + max = numCols; + end = -1; + break; + case XP_CURSOR_KEY_RIGHT: + incr = 1; + useWhat = (XP_S16*)colP; + max = numCols; + end = max; + break; + default: + XP_ASSERT( XP_FALSE ); } - *useWhat = (*useWhat + max) % max; + XP_ASSERT( incr != 0 ); - if ( !avoidOccupied - || !cellOccupied( board, *colP, *rowP, XP_TRUE ) ) { - result = XP_TRUE; - break; + for ( counter = max; ; --counter ) { + + *useWhat += incr; + + if ( (counter == 0) || (!canCycle && (*useWhat == end)) ) { + break; + } + + *useWhat = (*useWhat + max) % max; + + if ( !avoidOccupied + || !cellOccupied( board, *colP, *rowP, XP_TRUE ) ) { + result = XP_TRUE; + break; + } } } @@ -3115,7 +3265,7 @@ boardTileChanged( void* p_board, XP_U16 turn, TileBit bits ) { BoardCtxt* board = (BoardCtxt*)p_board; if ( turn == board->selPlayer ) { - board_invalTrayTiles( board, bits ); + board_invalTrayTiles( board, bits ); } } /* boardTileChanged */ diff --git a/xwords4/common/board.h b/xwords4/common/board.h index 1a5271bce..1a073abf6 100644 --- a/xwords4/common/board.h +++ b/xwords4/common/board.h @@ -33,19 +33,6 @@ extern "C" { #endif -typedef enum { - TRAY_HIDDEN, /* doesn't happen unless tray overlaps board */ - TRAY_REVERSED, - TRAY_REVEALED -} XW_TrayVisState; - -typedef enum { - OBJ_NONE, - OBJ_BOARD, - OBJ_SCORE, - OBJ_TRAY -} BoardObjectType; - typedef enum { /* keep these three together: for the cursor */ XP_KEY_NONE, @@ -67,7 +54,7 @@ typedef enum { BoardCtxt* board_make( MPFORMAL ModelCtxt* model, ServerCtxt* server, - DrawCtx* draw, XW_UtilCtxt* util ); + DrawCtx* draw, XW_UtilCtxt* util ); BoardCtxt* board_makeFromStream( MPFORMAL XWStreamCtxt* stream, ModelCtxt* model, ServerCtxt* server, DrawCtx* draw, XW_UtilCtxt* util, @@ -138,6 +125,8 @@ XP_Bool board_handleKey( BoardCtxt* board, XP_Key key ); #ifdef KEYBOARD_NAV /* void board_focusChange( BoardCtxt* board ); */ +XP_Bool board_focusChanged( BoardCtxt* board, BoardObjectType typ, + XP_Bool gained ); XP_Bool board_toggle_arrowDir( BoardCtxt* board ); #endif diff --git a/xwords4/common/boardp.h b/xwords4/common/boardp.h index f2e9c6e2c..c0c052ce3 100644 --- a/xwords4/common/boardp.h +++ b/xwords4/common/boardp.h @@ -125,6 +125,7 @@ struct BoardCtxt { BoardArrow boardArrow[MAX_NUM_PLAYERS]; #ifdef KEYBOARD_NAV BdCursorLoc bdCursor[MAX_NUM_PLAYERS]; + XP_Bool focusHasDived; #endif XP_U8 dividerLoc[MAX_NUM_PLAYERS]; /* 0 means left of 0th tile, etc. */ @@ -154,6 +155,7 @@ struct BoardCtxt { TileBit traySelBits[MAX_NUM_PLAYERS]; #ifdef KEYBOARD_NAV XP_U8 trayCursorLoc[MAX_NUM_PLAYERS]; + XP_U8 scoreCursorLoc; #endif XW_TrayVisState trayVisState; @@ -181,7 +183,7 @@ struct BoardCtxt { /* tray-related functions */ XP_Bool handlePenDownInTray( BoardCtxt* board, XP_U16 x, XP_U16 y ); XP_Bool handlePenUpTray( BoardCtxt* board, XP_U16 x, XP_U16 y ); -void drawTray( BoardCtxt* board, XP_Bool focussed ); +void drawTray( BoardCtxt* board ); TileBit continueTileDrag( BoardCtxt* board, XP_U16 x, XP_U16 y ); XP_Bool endTileDrag( BoardCtxt* board, XP_U16 x, XP_U16 y ); XP_Bool continueDividerDrag( BoardCtxt* board, XP_U16 x, XP_U16 y ); @@ -196,6 +198,9 @@ XP_Bool rectsIntersect( XP_Rect* rect1, XP_Rect* rect2 ); #ifdef KEYBOARD_NAV XP_Bool tray_moveCursor( BoardCtxt* board, XP_Key cursorKey ); XP_Bool tray_keyAction( BoardCtxt* board ); +DrawFocusState dfsFor( BoardCtxt* board, BoardObjectType obj ); +#else +# define dfsFor( board, obj ) DFS_NONE #endif #ifdef CPLUS diff --git a/xwords4/common/comtypes.h b/xwords4/common/comtypes.h index 8978a6209..3897076bb 100644 --- a/xwords4/common/comtypes.h +++ b/xwords4/common/comtypes.h @@ -61,6 +61,25 @@ typedef enum { ,TRI_ENAB_ENABLED } XP_TriEnable; +typedef enum { + DFS_NONE + ,DFS_TOP /* focus is on the object */ + ,DFS_DIVED /* focus is inside the object */ +} DrawFocusState; + +typedef enum { + TRAY_HIDDEN, /* doesn't happen unless tray overlaps board */ + TRAY_REVERSED, + TRAY_REVEALED +} XW_TrayVisState; + +typedef enum { + OBJ_NONE, + OBJ_BOARD, + OBJ_SCORE, + OBJ_TRAY +} BoardObjectType; + /* I'm going to try putting all forward "class" decls in the same file */ typedef struct BoardCtxt BoardCtxt; typedef struct CommMgrCtxt CommMgrCtxt; diff --git a/xwords4/common/config.mk b/xwords4/common/config.mk index 70d5f1a2f..da533d5ea 100644 --- a/xwords4/common/config.mk +++ b/xwords4/common/config.mk @@ -40,6 +40,7 @@ COMMONSRC = \ $(COMMONDIR)/movestak.c \ $(COMMONDIR)/strutils.c \ $(COMMONDIR)/vtabmgr.c \ + $(COMMONDIR)/dbgutil.c \ # PENDING: define this in terms of above!!! @@ -69,5 +70,6 @@ COMMON5 = \ $(COMMONOBJDIR)/movestak.o \ $(COMMONOBJDIR)/strutils.o \ $(COMMONOBJDIR)/vtabmgr.o \ + $(COMMONOBJDIR)/dbgutil.o \ COMMONOBJ = $(COMMON1) $(COMMON2) $(COMMON3) $(COMMON4) $(COMMON5) diff --git a/xwords4/common/draw.h b/xwords4/common/draw.h index f59f5e355..39b84607b 100644 --- a/xwords4/common/draw.h +++ b/xwords4/common/draw.h @@ -96,7 +96,7 @@ typedef struct DrawCtxVTable { XP_Bool DRAW_VTABLE_NAME(boardBegin) ( DrawCtx* dctx, const DictionaryCtxt* dict, const XP_Rect* rect, - XP_Bool hasfocus ); + DrawFocusState dfs ); void DRAW_VTABLE_NAME(boardFinished) ( DrawCtx* dctx ); /* rect is not const: set by callee */ @@ -104,7 +104,8 @@ typedef struct DrawCtxVTable { XP_S16 dist ); XP_Bool DRAW_VTABLE_NAME(trayBegin) ( DrawCtx* dctx, const XP_Rect* rect, - XP_U16 owner, XP_Bool hasfocus ); + XP_U16 owner, + DrawFocusState dfs ); void DRAW_VTABLE_NAME(trayFinished) ( DrawCtx* dctx ); void DRAW_VTABLE_NAME(measureRemText) ( DrawCtx* dctx, const XP_Rect* r, @@ -115,8 +116,7 @@ typedef struct DrawCtxVTable { XP_S16 nTilesLeft); void DRAW_VTABLE_NAME(scoreBegin) ( DrawCtx* dctx, const XP_Rect* rect, - XP_U16 numPlayers, - XP_Bool hasfocus ); + XP_U16 numPlayers, DrawFocusState dfs ); void DRAW_VTABLE_NAME(measureScoreText) ( DrawCtx* dctx, const XP_Rect* r, const DrawScoreInfo* dsi, @@ -161,8 +161,8 @@ typedef struct DrawCtxVTable { XWBonusType bonus, XP_Bool vert, HintAtts hintAtts ); #ifdef KEY_SUPPORT - void DRAW_VTABLE_NAME(drawTrayCursor) ( DrawCtx* dctx, const XP_Rect* rect ); - void DRAW_VTABLE_NAME(drawBoardCursor) ( DrawCtx* dctx, const XP_Rect* rect ); + void DRAW_VTABLE_NAME(drawCursor) ( DrawCtx* dctx, BoardObjectType typ, + const XP_Rect* rect ); #endif XP_UCHAR* DRAW_VTABLE_NAME(getMiniWText) ( DrawCtx* dctx, @@ -250,11 +250,9 @@ struct DrawCtx { #define draw_drawBoardArrow( dc, r, b, v, h ) \ CALL_DRAW_NAME4(drawBoardArrow,(dc),(r),(b), (v), (h)) #ifdef KEY_SUPPORT -# define draw_drawTrayCursor( dc, r ) CALL_DRAW_NAME1(drawTrayCursor,(dc),(r)) -# define draw_drawBoardCursor( dc, r ) CALL_DRAW_NAME1(drawBoardCursor,(dc),(r)) +# define draw_drawCursor( dc, t, r ) CALL_DRAW_NAME2(drawCursor,(dc),(t),(r)) #else -# define draw_drawTrayCursor( dc, r ) -# define draw_drawBoardCursor( dc, r ) +# define draw_drawCursor( dc, t, r ) #endif #define draw_getMiniWText( dc, b ) CALL_DRAW_NAME1(getMiniWText, (dc),(b) ) diff --git a/xwords4/common/tray.c b/xwords4/common/tray.c index 4566a2597..6a56611c2 100644 --- a/xwords4/common/tray.c +++ b/xwords4/common/tray.c @@ -19,6 +19,7 @@ #include "boardp.h" #include "engine.h" +#include "draw.h" #include "strutils.h" #ifdef CPLUS @@ -99,7 +100,7 @@ figureTrayTileRect( BoardCtxt* board, XP_U16 index, XP_Rect* rect ) } /* figureTileRect */ void -drawTray( BoardCtxt* board, XP_Bool focussed ) +drawTray( BoardCtxt* board ) { XP_Rect tileRect; short i; @@ -108,7 +109,7 @@ drawTray( BoardCtxt* board, XP_Bool focussed ) XP_S16 turn = board->selPlayer; if ( draw_trayBegin( board->draw, &board->trayBounds, turn, - focussed ) ) { + dfsFor( board, OBJ_TRAY ) ) ) { DictionaryCtxt* dictionary = model_getDictionary( board->model ); if ( board->eraseTray ) { @@ -175,13 +176,15 @@ drawTray( BoardCtxt* board, XP_Bool focussed ) board->dividerInvalid = XP_FALSE; } + drawPendingScore( board ); + #ifdef KEYBOARD_NAV - if ( showFaces ) { + if ( board->focusHasDived && board->focussed == OBJ_TRAY ) { TileBit cursorLoc = 1 << board->trayCursorLoc[turn]; if ( !!cursorLoc ) { XP_U16 index = indexForBits( cursorLoc ); figureTrayTileRect( board, index, &tileRect ); - draw_drawTrayCursor( board->draw, &tileRect ); + draw_drawCursor( board->draw, OBJ_TRAY, &tileRect ); } } #endif @@ -193,7 +196,6 @@ drawTray( BoardCtxt* board, XP_Bool focussed ) } } - drawPendingScore( board ); } /* drawTray */ static void diff --git a/xwords4/linux/cursesdraw.c b/xwords4/linux/cursesdraw.c index 97d311033..c5b6d50bb 100644 --- a/xwords4/linux/cursesdraw.c +++ b/xwords4/linux/cursesdraw.c @@ -27,6 +27,13 @@ #include "draw.h" #include "board.h" +typedef struct CursesDrawCtx { + DrawCtxVTable* vtable; + + WINDOW* boardWin; + +} CursesDrawCtx; + static void curses_draw_clearRect( DrawCtx* p_dctx, const XP_Rect* rectP ); static void @@ -52,49 +59,69 @@ eraseRect( CursesDrawCtx* dctx, const XP_Rect* rect ) } } /* eraseRect */ +static void +cursesHiliteRect( WINDOW* window, const XP_Rect* rect ) +{ + int right, width, x, y; + LOG_FUNC(); + width = rect->width; + right = width + rect->left; + wstandout( window ); + for ( y = rect->top; y < rect->top + rect->height; ++y ) { + for ( x = rect->left; x < right; ++x ) { + chtype cht = mvwinch( window, y, x ); + char ch = cht & A_CHARTEXT; + mvwaddch( window, y, x, ch ); + } + } + wstandend( window ); +} + static void curses_draw_destroyCtxt( DrawCtx* XP_UNUSED(p_dctx) ) { // CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx; } /* draw_setup */ +static void +drawFocusRect( CursesDrawCtx* dctx, DrawFocusState dfs, const XP_Rect* rect ) +{ + WINDOW* boardWin = dctx->boardWin; + if ( dfs == DFS_NONE ) { + drawRect( boardWin, rect, '|', '-' ); + } else if ( dfs == DFS_TOP ) { + drawRect( boardWin, rect, '*', '*' ); + } else if ( dfs == DFS_DIVED ) { + drawRect( boardWin, rect, '+', '+' ); + } else { + XP_ASSERT(0); + } +} + static XP_Bool curses_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* XP_UNUSED(dict), - const XP_Rect* rect, XP_Bool hasfocus ) + const XP_Rect* rect, DrawFocusState dfs ) { CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx; - if ( hasfocus ) { - drawRect( dctx->boardWin, rect, '+', '+' ); - } else { - drawRect( dctx->boardWin, rect, '|', '-' ); - } + drawFocusRect( dctx, dfs, rect ); return XP_TRUE; } /* draw_finish */ static XP_Bool curses_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, - XP_U16 XP_UNUSED(owner), XP_Bool hasfocus ) + XP_U16 XP_UNUSED(owner), DrawFocusState dfs ) { CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx; - if ( hasfocus ) { - drawRect( dctx->boardWin, rect, '+', '+' ); - } else { - drawRect( dctx->boardWin, rect, '|', '-' ); - } + drawFocusRect( dctx, dfs, rect ); return XP_TRUE; } /* draw_finish */ static void curses_draw_scoreBegin( DrawCtx* p_dctx, const XP_Rect* rect, - XP_U16 XP_UNUSED(numPlayers), XP_Bool hasfocus ) + XP_U16 XP_UNUSED(numPlayers), DrawFocusState dfs ) { CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx; - if ( hasfocus ) { - drawRect( dctx->boardWin, rect, '+', '+' ); - } else { - drawRect( dctx->boardWin, rect, '|', '-' ); - } - + drawFocusRect( dctx, dfs, rect ); } /* curses_draw_scoreBegin */ static void @@ -154,7 +181,9 @@ formatScoreText( XP_UCHAR* buf, const DrawScoreInfo* dsi ) label = toupper(label); } - len = sprintf( buf, "%s[%c] %s (%d)", (dsi->isTurn?"->":" "), + len = sprintf( buf, "%c:%c [%c] %s (%d)", + (dsi->isTurn? 'T' : ' '), + (dsi->selected? 'S' : ' '), label, dsi->name, nTilesLeft ); while ( len < SCORE_COL ) { ++len; @@ -236,20 +265,12 @@ curses_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner, curses_draw_clearRect( p_dctx, rOuter ); - if ( dsi->selected ) { - wstandout( dctx->boardWin ); - } /* first blank out the whole thing! */ mvwhline( dctx->boardWin, y, rOuter->left, ' ', rOuter->width ); /* print the name and turn/remoteness indicator */ formatScoreText( buf, dsi ); mvwprintw( dctx->boardWin, y, rOuter->left, buf ); - - if ( dsi->selected ) { - wstandend( dctx->boardWin ); - } - /* (void)wcolor_set( dctx->boardWin, prev, NULL ); */ } /* curses_draw_score_drawPlayer */ static XP_Bool @@ -373,23 +394,13 @@ curses_draw_drawBoardArrow( DrawCtx* p_dctx, const XP_Rect* rect, } /* curses_draw_drawBoardArrow */ static void -curses_draw_drawBoardCursor( DrawCtx* p_dctx, const XP_Rect* rect ) +curses_draw_drawCursor( DrawCtx* p_dctx, BoardObjectType XP_UNUSED(typ), + const XP_Rect* rect ) { CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx; - chtype curChar = mvwinch(dctx->boardWin, rect->top, rect->left ); - wstandout( dctx->boardWin ); - mvwaddch( dctx->boardWin, rect->top, rect->left, curChar); - wstandend( dctx->boardWin ); + cursesHiliteRect( dctx->boardWin, rect ); } /* curses_draw_drawBoardCursor */ -static void -curses_draw_drawTrayCursor( DrawCtx* p_dctx, const XP_Rect* rect ) -{ - CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx; - wmove( dctx->boardWin, rect->top, rect->left ); - whline( dctx->boardWin, 'v', rect->width ); -} /* curses_draw_drawTrayCursor */ - static void curses_draw_clearRect( DrawCtx* p_dctx, const XP_Rect* rectP ) { @@ -490,8 +501,7 @@ cursesDrawCtxtMake( WINDOW* boardWin ) SET_VTABLE_ENTRY( dctx->vtable, draw_drawTrayDivider, curses ); SET_VTABLE_ENTRY( dctx->vtable, draw_drawBoardArrow, curses ); - SET_VTABLE_ENTRY( dctx->vtable, draw_drawBoardCursor, curses ); - SET_VTABLE_ENTRY( dctx->vtable, draw_drawTrayCursor, curses ); + SET_VTABLE_ENTRY( dctx->vtable, draw_drawCursor, curses ); SET_VTABLE_ENTRY( dctx->vtable, draw_clearRect, curses ); diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index 820d2810b..2e48d06f1 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -991,7 +991,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) signal( SIGWINCH, SIGWINCH_handler ); initCurses( &globals ); - globals.draw = (CursesDrawCtx*)cursesDrawCtxtMake( globals.boardWin ); + globals.draw = (struct CursesDrawCtx*)cursesDrawCtxtMake( globals.boardWin ); gameID = (XP_U16)util_getCurSeconds( globals.cGlobals.params->util ); game_makeNewGame( MEMPOOL &globals.cGlobals.game, ¶ms->gi, diff --git a/xwords4/linux/cursesmain.h b/xwords4/linux/cursesmain.h index 23019e063..44d71ba24 100644 --- a/xwords4/linux/cursesmain.h +++ b/xwords4/linux/cursesmain.h @@ -41,14 +41,6 @@ #include "util.h" /* #include "compipe.h" */ -typedef struct CursesDrawCtx { - DrawCtxVTable* vtable; - - WINDOW* boardWin; -/* WINDOW* trayWin; */ - -} CursesDrawCtx; - typedef struct CursesAppGlobals CursesAppGlobals; typedef XP_Bool (*EventFunc)(CursesAppGlobals* globals, int ch); @@ -62,7 +54,7 @@ typedef XP_Bool (*EventFunc)(CursesAppGlobals* globals, int ch); struct CursesAppGlobals { CommonGlobals cGlobals; - CursesDrawCtx* draw; + struct CursesDrawCtx* draw; DictionaryCtxt* dictionary; EngineCtxt* engine; diff --git a/xwords4/linux/gtkdraw.c b/xwords4/linux/gtkdraw.c index 30598440b..0ea3e082b 100644 --- a/xwords4/linux/gtkdraw.c +++ b/xwords4/linux/gtkdraw.c @@ -240,7 +240,7 @@ gtk_draw_destroyCtxt( DrawCtx* p_dctx ) static XP_Bool gtk_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* XP_UNUSED(dict), - const XP_Rect* rect, XP_Bool XP_UNUSED(hasfocus) ) + const XP_Rect* rect, DrawFocusState XP_UNUSED(dfs) ) { GdkRectangle gdkrect; GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; @@ -402,7 +402,7 @@ gtk_draw_invertCell( DrawCtx* XP_UNUSED(p_dctx), static XP_Bool gtk_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 owner, - XP_Bool XP_UNUSED(hasfocus) ) + DrawFocusState XP_UNUSED(dfs) ) { GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; XP_Rect clip = *rect; @@ -574,7 +574,7 @@ gtk_draw_drawBoardArrow( DrawCtx* p_dctx, const XP_Rect* rectP, static void gtk_draw_scoreBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 XP_UNUSED(numPlayers), - XP_Bool XP_UNUSED(hasfocus) ) + DrawFocusState XP_UNUSED(dfs) ) { GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; diff --git a/xwords4/palm/Makefile b/xwords4/palm/Makefile index a255f2f3f..25c917247 100644 --- a/xwords4/palm/Makefile +++ b/xwords4/palm/Makefile @@ -164,7 +164,7 @@ BITMAP_RSRCS = \ # INCLUDES += -I/usr/local/share/palmdev/sdk-5r3/Extensions/ExpansionMgr INCLUDES += -I/usr/local/share/palmdev/sdk-5r3/include/Extensions/Bluetooth -XWFEATURE_FIVEWAY = -DXWFEATURE_FIVEWAY +XWFEATURE_FIVEWAY = -DXWFEATURE_FIVEWAY -DKEYBOARD_NAV ifneq (x$(XWFEATURE_FIVEWAY)x, xx) INCLUDES += -I/usr/local/share/palmdev/Handspring5 diff --git a/xwords4/palm/common.rcp.pre b/xwords4/palm/common.rcp.pre index d58e372a8..1c33f3152 100644 --- a/xwords4/palm/common.rcp.pre +++ b/xwords4/palm/common.rcp.pre @@ -94,6 +94,11 @@ USABLE NOFRAME MENUID XW_MAIN_MENU_ID BEGIN +#ifdef XWFEATURE_FIVEWAY + GADGET ID XW_SCOREBOARD_GADGET_ID AT (0 0 1 1) USABLE + GADGET ID XW_BOARD_GADGET_ID AT (0 0 1 1) USABLE + GADGET ID XW_TRAY_GADGET_ID AT (0 0 1 1) USABLE +#endif BUTTON "" XW_MAIN_FLIP_BUTTON_ID AT (PALM_FLIP_LEFT PALM_BOARD_TOP FLIP_BUTTON_WIDTH FLIP_BUTTON_HEIGHT) NOFRAME @@ -136,9 +141,15 @@ NAVIGATION ID XW_MAIN_FORM INITIALSTATE kFrmNavHeaderFlagsObjectFocusStartState INITIALOBJECTID XW_MAIN_FLIP_BUTTON_ID BEGIN + ID XW_SCOREBOARD_GADGET_ID + ID XW_BOARD_GADGET_ID + ID XW_MAIN_FLIP_BUTTON_ID ID XW_MAIN_VALUE_BUTTON_ID ID XW_MAIN_HINT_BUTTON_ID + + ID XW_TRAY_GADGET_ID + ID XW_MAIN_SHOWTRAY_BUTTON_ID ID XW_MAIN_HIDE_BUTTON_ID ID XW_MAIN_JUGGLE_BUTTON_ID diff --git a/xwords4/palm/palmdraw.c b/xwords4/palm/palmdraw.c index 716ff2fba..b20fea9a5 100644 --- a/xwords4/palm/palmdraw.c +++ b/xwords4/palm/palmdraw.c @@ -1,4 +1,4 @@ -/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */ +/* -*-mode: C; fill-column: 77; c-basic-offset: 4; compile-command: "make ARCH=68K_ONLY MEMDEBUG=TRUE";-*- */ /* * Copyright 1999 - 2001 by Eric House (xwords@eehouse.org). All rights reserved. * @@ -19,8 +19,12 @@ #include #include +#ifdef XWFEATURE_FIVEWAY +# include +#endif #include "draw.h" +#include "dbgutil.h" #include "palmmain.h" #include "xwords4defines.h" @@ -48,7 +52,7 @@ static void palm_bnw_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rOuter, const DrawScoreInfo* dsi ); static XP_Bool palm_bnw_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, - XP_U16 owner, XP_Bool hasfocus ); + XP_U16 owner, DrawFocusState dfs ); static void palm_bnw_draw_trayFinished( DrawCtx* p_dctx ); static void palm_clr_draw_clearRect( DrawCtx* p_dctx, const XP_Rect* rectP ); static void palm_draw_drawMiniWindow( DrawCtx* p_dctx, const XP_UCHAR* text, @@ -124,6 +128,65 @@ bitmapInRect( PalmDrawCtx* dctx, Int16 resID, const XP_Rect* rectP ) drawBitmapAt( (DrawCtx*)dctx, resID, left, top ); } /* bitmapInRect */ +#ifdef KEYBOARD_NAV +#ifdef XWFEATURE_FIVEWAY +static void +drawFocusRect( PalmDrawCtx* dctx, const XP_Rect* rect ) +{ + XP_Rect r; + Err err; + PalmAppGlobals* globals = dctx->globals; + + XP_ASSERT( dctx->doHiRes ); + r.left = rect->left >> 1; + r.top = rect->top >> 1; + r.width = rect->width >> 1; + r.height = rect->height >> 1; + ++r.height; + ++r.width; + insetRect( &r, 3 ); /* draw inside the thing */ + rect = &r; + + XP_LOGF( "%s: HsNavDrawFocusRing at {%d,%d,%d,%d}", __FUNCTION__, + rect->left, rect->top, rect->width, rect->height ); + + err = HsNavDrawFocusRing( globals->mainForm, XW_SCOREBOARD_GADGET_ID, 0, + (RectangleType*)rect, + hsNavFocusRingStyleObjectTypeDefault, false ); +/* XP_LOGF( "%s: HsNavDrawFocusRing => %x", __FUNCTION__, err ); */ +} +#else +# define drawFocusRect( a, b ) +#endif + +static void +dfsDrawIf( PalmDrawCtx* dctx, BoardObjectType obj ) +{ + if ( dctx->topFocusObj == obj ) { + drawFocusRect( dctx, &dctx->topFocusRect ); + dctx->topFocusObj = OBJ_NONE; + } +} + +static void +dfsCopyIf( PalmDrawCtx* dctx, DrawFocusState dfs, + const XP_Rect* rect, BoardObjectType obj ) +{ + XP_LOGF( "%s(%s, %s)", __FUNCTION__, DrawFocusState_2str(dfs), + BoardObjectType_2str(obj) ); + if ( dfs == DFS_TOP ) { + dctx->topFocusObj = obj; + XP_MEMCPY( &dctx->topFocusRect, rect, sizeof(dctx->topFocusRect) ); + } else /* if ( dfs == DFS_DIVED ) */ { + dctx->topFocusObj = OBJ_NONE; + } +} + +#else +# define dfsCopyIf( dctx, dfs, rect, obj ) +# define dfsDrawIf( dctx, obj ) +#endif + # define BMP_WIDTH 16 # define BMP_HT 16 @@ -224,7 +287,7 @@ checkFontOffsets( PalmDrawCtx* dctx, const DictionaryCtxt* dict ) static XP_Bool palm_common_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* dict, - const XP_Rect* rect, XP_Bool XP_UNUSED(hasfocus) ) + const XP_Rect* rect, DrawFocusState dfs ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; PalmAppGlobals* globals = dctx->globals; @@ -234,13 +297,15 @@ palm_common_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* dict, checkFontOffsets( dctx, dict ); + dfsCopyIf( dctx, dfs, rect, OBJ_BOARD ); + return XP_TRUE; } /* palm_common_draw_boardBegin */ #ifdef COLOR_SUPPORT static XP_Bool palm_clr_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* dict, - const XP_Rect* rect, XP_Bool hasfocus ) + const XP_Rect* rect, DrawFocusState dfs ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; @@ -252,14 +317,16 @@ palm_clr_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* dict, HIGHRES_PUSH_NOPOP(dctx); - palm_common_draw_boardBegin( p_dctx, dict, rect, hasfocus ); + palm_common_draw_boardBegin( p_dctx, dict, rect, dfs ); return XP_TRUE; } /* palm_clr_draw_boardBegin */ static void -palm_clr_draw_boardFinished( DrawCtx* XP_UNUSED(p_dctx) ) +palm_clr_draw_boardFinished( DrawCtx* p_dctx ) { + dfsDrawIf( (PalmDrawCtx*)p_dctx, OBJ_BOARD ); + WinPopDrawState(); } /* palm_clr_draw_boardFinished */ @@ -518,7 +585,7 @@ palm_draw_invertCell( DrawCtx* p_dctx, const XP_Rect* rect ) static XP_Bool palm_clr_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, - XP_U16 owner, XP_Bool hasfocus ) + XP_U16 owner, DrawFocusState dfs ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; @@ -531,21 +598,23 @@ palm_clr_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, HIGHRES_PUSH_NOPOP(dctx); - palm_bnw_draw_trayBegin( p_dctx, rect, owner, hasfocus ); + palm_bnw_draw_trayBegin( p_dctx, rect, owner, dfs ); return XP_TRUE; } /* palm_clr_draw_trayBegin */ static XP_Bool palm_bnw_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 XP_UNUSED(owner), - XP_Bool XP_UNUSED(hasfocus) ) + DrawFocusState dfs ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; + dfsCopyIf( dctx, dfs, rect, OBJ_TRAY ); + WinGetClip( &dctx->oldTrayClip ); WinSetClip( (RectangleType*)rect ); return XP_TRUE; -} /* palm_draw_trayBegin */ +} /* palm_bnw_draw_trayBegin */ static void palm_clr_draw_trayFinished( DrawCtx* p_dctx ) @@ -558,6 +627,7 @@ static void palm_bnw_draw_trayFinished( DrawCtx* p_dctx ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; + dfsDrawIf( dctx, OBJ_TRAY ); WinSetClip( &dctx->oldTrayClip ); } /* palm_draw_trayFinished */ @@ -579,6 +649,15 @@ smallBoldStringAt( const char* str, XP_U16 len, XP_S16 x, XP_U16 y ) WinSetScalingMode( oldMode ); } /* smallBoldStringAt */ +static void +adjustTileRect( XP_Rect* r, XP_U16 doubler ) +{ + r->width -= 3 * doubler; + r->height -= 3 * doubler; + r->top += 2 * doubler; + r->left += 2 * doubler; +} + static void palm_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letters, XP_Bitmap bitmap, @@ -596,10 +675,7 @@ palm_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, draw_clearRect( p_dctx, &localR ); - localR.width -= 3 * doubler; - localR.height -= 3 * doubler; - localR.top += 2 * doubler; - localR.left += 2 * doubler; + adjustTileRect( &localR, doubler ); /* this will fill it with the tile background color */ WinEraseRectangle( (const RectangleType*)&localR, 0 ); @@ -747,10 +823,12 @@ palm_clr_draw_drawBoardArrow( DrawCtx* p_dctx, const XP_Rect* rectP, static void palm_draw_scoreBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 XP_UNUSED(numPlayers), - XP_Bool XP_UNUSED(hasfocus) ) + DrawFocusState dfs ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; + dfsCopyIf( dctx, dfs, rect, OBJ_SCORE ); + HIGHRES_PUSH( dctx ); WinGetClip( &dctx->oldScoreClip ); @@ -1082,6 +1160,7 @@ static void palm_draw_scoreFinished( DrawCtx* p_dctx ) { PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; + dfsDrawIf( dctx, OBJ_SCORE ); WinSetClip( &dctx->oldScoreClip ); HIGHRES_POP(dctx); @@ -1328,6 +1407,32 @@ palm_draw_eraseMiniWindow( DrawCtx* p_dctx, const XP_Rect* XP_UNUSED(rect), } } /* palm_draw_eraseMiniWindow */ +#ifdef KEYBOARD_NAV +static void +palm_draw_drawCursor( DrawCtx* p_dctx, BoardObjectType obj, + const XP_Rect* rect ) +{ + XP_Rect localR; + + if ( OBJ_TRAY == obj ) { + PalmDrawCtx* dctx = (PalmDrawCtx*)p_dctx; + XP_U16 doubler = dctx->doHiRes? 2 : 1; + + localR = *rect; + rect = &localR; + adjustTileRect( &localR, doubler ); + + localR.left += 2; + localR.top += 1; + localR.width -= 4; + localR.height -= 2; + + insetRect( &localR, 1 ); + } + drawFocusRect( (PalmDrawCtx*)p_dctx, rect ); +} +#endif + static void draw_doNothing( DrawCtx* XP_UNUSED(dctx), ... ) { @@ -1388,6 +1493,10 @@ palm_drawctxt_make( MPFORMAL GraphicsAbility able, SET_VTABLE_ENTRY( dctx->vtable, draw_drawMiniWindow, palm ); SET_VTABLE_ENTRY( dctx->vtable, draw_eraseMiniWindow, palm ); +#ifdef KEYBOARD_NAV + SET_VTABLE_ENTRY( dctx->vtable, draw_drawCursor, palm ); +#endif + if ( able == COLOR ) { #ifdef COLOR_SUPPORT SET_VTABLE_ENTRY( dctx->vtable, draw_boardBegin, palm_clr ); diff --git a/xwords4/palm/palmmain.c b/xwords4/palm/palmmain.c index cba8fb4da..3b12b88ec 100644 --- a/xwords4/palm/palmmain.c +++ b/xwords4/palm/palmmain.c @@ -2024,6 +2024,48 @@ hresRect( PalmAppGlobals* globals, RectangleType* r ) } } +#ifdef XWFEATURE_FIVEWAY +static XP_Bool +handleChangeFocus( PalmAppGlobals* globals, const EventType* event, + XP_Bool* drawP ) +{ + XP_Bool handled = XP_FALSE; + XP_U16 objectID = event->data.frmObjectFocusTake.objectID; + XP_ASSERT( &event->data.frmObjectFocusTake.objectID + == &event->data.frmObjectFocusLost.objectID ); + +/* XP_LOGF( "%s(%d,%s)", __FUNCTION__, objectID, */ +/* (event->eType == frmObjectFocusTakeEvent? "take":"lost") ); */ + + handled = ( objectID == XW_BOARD_GADGET_ID + || objectID == XW_SCOREBOARD_GADGET_ID + || objectID == XW_TRAY_GADGET_ID ); + + if ( handled ) { + XP_Bool take = event->eType == frmObjectFocusTakeEvent; + BoardObjectType typ = (objectID - XW_BOARD_GADGET_ID) + OBJ_BOARD; + *drawP = board_focusChanged( globals->game.board, typ, take ); + if ( take ) { + FrmSetFocus( globals->mainForm, + FrmGetObjectIndex( globals->mainForm, objectID ) ); + } + } + + return handled; +} /* handleChangeFocus */ + +static void +checkSetFocus( PalmAppGlobals* globals ) +{ + BoardObjectType typ = board_getFocusOwner( globals->game.board ); + XP_U16 objectID = XW_BOARD_GADGET_ID + (typ - OBJ_BOARD); + XP_LOGF( "%s: FrmSetFocus(%d)", __FUNCTION__, objectID ); + FrmSetFocus( globals->mainForm, + FrmGetObjectIndex( globals->mainForm, objectID ) ); +} + +#endif + /***************************************************************************** * ****************************************************************************/ @@ -2439,6 +2481,13 @@ mainViewHandleEvent( EventPtr event ) } break; +#ifdef XWFEATURE_FIVEWAY + case frmObjectFocusTakeEvent: + case frmObjectFocusLostEvent: + handled = handleChangeFocus( globals, event, &draw ); + break; +#endif + case keyDownEvent: { XP_Key xpkey = XP_KEY_NONE; Int16 ch = event->data.keyDown.chr; @@ -2453,6 +2502,27 @@ mainViewHandleEvent( EventPtr event ) case backspaceChr: xpkey = XP_CURSOR_KEY_DEL; break; + +#ifdef XWFEATURE_FIVEWAY + case vchrRockerCenter: + xpkey = XP_RETURN_KEY; + break; + case vchrRockerLeft: + xpkey = XP_CURSOR_KEY_LEFT; + break; + case vchrRockerRight: + xpkey = XP_CURSOR_KEY_RIGHT; + break; + case vchrRockerUp: + xpkey = XP_CURSOR_KEY_UP; + break; + case vchrRockerDown: + xpkey = XP_CURSOR_KEY_DOWN; + break; + case chrSpace: + xpkey = XP_FOCUSCHANGE_KEY; + break; +#endif default: /* I'm not interested in being dependent on a particular version of the OS, (can't manage to link against the intl library @@ -2469,6 +2539,11 @@ mainViewHandleEvent( EventPtr event ) } if ( xpkey != XP_KEY_NONE ) { draw = board_handleKey( globals->game.board, xpkey ); +#ifdef XWFEATURE_FIVEWAY + if ( xpkey == XP_FOCUSCHANGE_KEY ) { + checkSetFocus( globals ); + } +#endif } handled = draw; } diff --git a/xwords4/palm/palmmain.h b/xwords4/palm/palmmain.h index fab5c8f68..9d7d9315c 100644 --- a/xwords4/palm/palmmain.h +++ b/xwords4/palm/palmmain.h @@ -89,6 +89,11 @@ typedef struct PalmDrawCtx { XP_LangCode fontLangCode; PalmFontHtInfo* fontHtInfo; +#ifdef XWFEATURE_FIVEWAY + BoardObjectType topFocusObj; + XP_Rect topFocusRect; +#endif + union { struct { XP_U8 reserved; /* make CW compiler happy */ diff --git a/xwords4/palm/xwords4defines.h b/xwords4/palm/xwords4defines.h index 9e6162c9a..00aec5b2f 100644 --- a/xwords4/palm/xwords4defines.h +++ b/xwords4/palm/xwords4defines.h @@ -289,6 +289,15 @@ # endif #endif + +#ifdef XWFEATURE_FIVEWAY +/* These should be in same order as BoardObjectType */ +# define XW_BOARD_GADGET_ID 3001 +# define XW_SCOREBOARD_GADGET_ID 3002 +# define XW_TRAY_GADGET_ID 3003 +#endif + + /* These aren't part of the hide/show thing as they're displayed only * explicitly byother controls */ #define XW_PREFS_PHONIES_LIST_ID 2750