Use new keydown/up APIs from linux, and add key support and drawing

changes to implement keyboard navigation/focus in gtk port.
This commit is contained in:
ehouse 2007-01-06 17:46:02 +00:00
parent bce76a3d34
commit 23fcaa65ab
6 changed files with 172 additions and 74 deletions

View file

@ -340,8 +340,8 @@ handleSpace( CursesAppGlobals* globals )
XP_Bool handled;
checkAssignFocus( globals->cGlobals.game.board );
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
XP_RAISEFOCUS_KEY, &handled );
globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
XP_RAISEFOCUS_KEY, &handled );
return XP_TRUE;
} /* handleSpace */
@ -349,8 +349,8 @@ static XP_Bool
handleRet( CursesAppGlobals* globals )
{
XP_Bool handled;
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
XP_RETURN_KEY, &handled );
globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
XP_RETURN_KEY, &handled );
return XP_TRUE;
} /* handleRet */
@ -437,8 +437,8 @@ static XP_Bool
handleBackspace( CursesAppGlobals* globals )
{
XP_Bool handled;
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
XP_CURSOR_KEY_DEL, &handled );
globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
XP_CURSOR_KEY_DEL, &handled );
return XP_TRUE;
} /* handleBackspace */
@ -482,46 +482,6 @@ MenuList sharedMenuList[] = {
};
#ifdef KEYBOARD_NAV
static XP_Bool
shiftFocus( CursesAppGlobals* globals, XP_Key key )
{
BoardCtxt* board = globals->cGlobals.game.board;
XP_Bool handled = XP_FALSE;
do { /* allow break */
XP_Bool forward;
BoardObjectType nxt;
if ( key == XP_CURSOR_KEY_DOWN || key == XP_CURSOR_KEY_RIGHT ) {
forward = XP_TRUE;
} else if ( key == XP_CURSOR_KEY_UP || key == XP_CURSOR_KEY_LEFT ) {
forward = XP_FALSE;
} else {
break;
}
switch( board_getFocusOwner( board ) ) {
case OBJ_NONE:
XP_ASSERT( 0 ); /* not in curses anyway */
break;
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;
}
handled = board_focusChanged( board, nxt, XP_TRUE );
if ( handled ) {
changeMenuForFocus( globals, nxt );
}
} while ( 0 );
return handled;
}
static XP_Bool
handleFocusKey( CursesAppGlobals* globals, XP_Key key )
{
@ -530,9 +490,14 @@ handleFocusKey( CursesAppGlobals* globals, XP_Key key )
checkAssignFocus( globals->cGlobals.game.board );
draw = board_handleKey( globals->cGlobals.game.board, key, &handled );
draw = board_handleKeyUp( globals->cGlobals.game.board, key, &handled );
if ( !handled ) {
draw = shiftFocus( globals, key ) || draw;
BoardObjectType nxt;
BoardObjectType order[] = { OBJ_BOARD, OBJ_SCORE, OBJ_TRAY };
draw = linShiftFocus( &globals->cGlobals, key, order, &nxt ) || draw;
if ( nxt != OBJ_NONE ) {
changeMenuForFocus( globals, nxt );
}
}
globals->doDraw = draw || globals->doDraw;
@ -1037,8 +1002,8 @@ passKeyToBoard( CursesAppGlobals* globals, char ch )
XP_Bool handled = ch >= 'a' && ch <= 'z';
if ( handled ) {
ch += 'A' - 'a';
globals->doDraw = board_handleKey( globals->cGlobals.game.board,
ch, NULL );
globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
ch, NULL );
}
return handled;
} /* passKeyToBoard */

View file

@ -1,6 +1,6 @@
/* -*- mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* -*- mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 1997-2005 by Eric House (xwords@eehouse.org). All rights reserved.
* Copyright 1997-2007 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
@ -256,12 +256,38 @@ gtk_draw_boardBegin( DrawCtx* p_dctx, const DictionaryCtxt* XP_UNUSED(dict),
} /* draw_finish */
static void
gtk_draw_objFinished( DrawCtx* XP_UNUSED(p_dctx),
BoardObjectType XP_UNUSED(typ),
const XP_Rect* XP_UNUSED(rect),
DrawFocusState XP_UNUSED(dfs) )
drawFocusFrame( GtkDrawCtx* dctx, const XP_Rect* r )
{
// GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect rectInset = *r;
XP_U16 i;
XP_U16 targetDim;
targetDim = XP_MIN( rectInset.width, rectInset.height );
targetDim >>= 1;
gdk_gc_set_foreground( dctx->drawGC, &dctx->black );
for ( i = 0; i < 5; ++i ) {
insetRect( &rectInset, 1 );
if ( rectInset.width < targetDim || rectInset.height < targetDim ) {
break;
}
gdk_draw_rectangle( DRAW_WHAT(dctx),
dctx->drawGC,
FALSE,
rectInset.left, rectInset.top,
rectInset.width+1, rectInset.height+1 );
}
}
static void
gtk_draw_objFinished( DrawCtx* p_dctx, BoardObjectType XP_UNUSED(typ),
const XP_Rect* rect, DrawFocusState dfs )
{
if ( dfs == DFS_TOP ) {
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
drawFocusFrame( dctx, rect );
}
} /* draw_finished */
static void
@ -378,6 +404,10 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
drawHintBorders( dctx, rect, hintAtts );
if ( (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
return XP_TRUE;
} /* gtk_draw_drawCell */
@ -404,12 +434,14 @@ gtk_draw_invertCell( DrawCtx* XP_UNUSED(p_dctx),
static XP_Bool
gtk_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 owner,
DrawFocusState XP_UNUSED(dfs) )
DrawFocusState dfs )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect clip = *rect;
insetRect( &clip, -1 );
dctx->trayOwner = owner;
dctx->topFocus = dfs == DFS_TOP;
/* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)&clip ); */
return XP_TRUE;
} /* gtk_draw_trayBegin */
@ -476,11 +508,16 @@ gtk_draw_drawTile( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
insetR.width, insetR.height);
}
}
if ( !dctx->topFocus && (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
} /* gtk_draw_drawTile */
static void
gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect,
CellFlags XP_UNUSED(flags) )
CellFlags flags )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect r = *rect;
@ -502,6 +539,10 @@ gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect,
draw_string_at( dctx, dctx->layout[LAYOUT_LARGE], "?",
&r, XP_GTK_JUST_CENTER,
&dctx->playerColors[dctx->trayOwner], NULL );
if ( !dctx->topFocus && (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
} /* gtk_draw_drawTileBack */
static void
@ -577,12 +618,13 @@ 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),
DrawFocusState XP_UNUSED(dfs) )
DrawFocusState dfs )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
/* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)rect ); */
eraseRect( dctx, rect );
dctx->topFocus = dfs == DFS_TOP;
} /* gtk_draw_scoreBegin */
static void
@ -702,12 +744,16 @@ gtk_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner,
draw_string_at( dctx, dctx->layout[LAYOUT_SMALL], scoreBuf,
rInner, XP_GTK_JUST_CENTER,
&dctx->playerColors[dsi->playerNum], NULL );
if ( !dctx->topFocus && ((dsi->flags & CELL_ISCURSOR) != 0) ) {
drawFocusFrame( dctx, rOuter );
}
} /* gtk_draw_score_drawPlayer */
static void
gtk_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect,
XP_S16 score, XP_U16 XP_UNUSED(playerNum),
CellFlags XP_UNUSED(flags) )
CellFlags flags )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
char buf[5];
@ -733,6 +779,10 @@ gtk_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect,
draw_string_at( dctx, dctx->layout[LAYOUT_SMALL], buf,
&localR, XP_GTK_JUST_BOTTOMRIGHT,
&dctx->black, NULL );
if ( !dctx->topFocus && (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
} /* gtk_draw_score_pendingScore */
static void

View file

@ -153,17 +153,20 @@ button_release_event( GtkWidget* XP_UNUSED(widget), GdkEventMotion *event,
return 1;
} /* button_release_event */
static gint
key_release_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event,
GtkAppGlobals* globals )
static XP_Key
evtToXPKey( GdkEventKey* event, XP_Bool* movesCursorP )
{
XP_Key xpkey = XP_KEY_NONE;
XP_Bool movesCursor = XP_FALSE;
guint keyval = event->keyval;
XP_LOGF( "got key 0x%x", keyval );
switch( keyval ) {
switch( keyval ) {
case GDK_Return:
xpkey = XP_RETURN_KEY;
break;
case GDK_space:
xpkey = XP_RAISEFOCUS_KEY;
break;
case GDK_Left:
xpkey = XP_CURSOR_KEY_LEFT;
@ -191,16 +194,43 @@ key_release_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event,
xpkey = toupper(keyval);
break;
}
return FALSE;
}
*movesCursorP = movesCursor;
return xpkey;
} /* evtToXPKey */
static gint
key_press_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event,
GtkAppGlobals* globals )
{
XP_Bool handled = XP_FALSE;
XP_Bool movesCursor;
XP_Key xpkey = evtToXPKey( event, &movesCursor );
if ( xpkey != XP_KEY_NONE ) {
if ( board_handleKeyDown( globals->cGlobals.game.board, xpkey,
&handled ) ) {
board_draw( globals->cGlobals.game.board );
}
}
return 1;
}
static gint
key_release_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event,
GtkAppGlobals* globals )
{
XP_Bool handled = XP_FALSE;
XP_Bool movesCursor;
XP_Key xpkey = evtToXPKey( event, &movesCursor );
if ( xpkey != XP_KEY_NONE ) {
XP_Bool handled;
XP_Bool draw;
draw = board_handleKey( globals->cGlobals.game.board, xpkey, &handled );
draw = board_handleKeyUp( globals->cGlobals.game.board, xpkey, &handled );
if ( movesCursor || !handled ) {
XP_LOGF( "need to handle focus shift" );
if ( movesCursor && !handled ) {
BoardObjectType order[] = { OBJ_SCORE, OBJ_BOARD, OBJ_TRAY };
draw = linShiftFocus( &globals->cGlobals, xpkey, order,
NULL ) || draw;
}
if ( draw ) {
@ -208,7 +238,7 @@ key_release_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event,
}
}
return 0;
return handled? 1 : 0; /* gtk will do something with the key if 0 returned */
} /* key_release_event */
#ifdef MEM_DEBUG
@ -1134,7 +1164,7 @@ pentimer_idle_func( gpointer data )
GtkAppGlobals* globals = (GtkAppGlobals*)data;
struct timeval tv;
XP_Bool callAgain = XP_TRUE;
gettimeofday( &tv, NULL );
if ( (tv.tv_usec - globals->penTv.tv_usec) >= globals->penTimerInterval) {
@ -1788,6 +1818,8 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
g_signal_connect( GTK_OBJECT(drawing_area), "button_release_event",
G_CALLBACK(button_release_event), &globals );
g_signal_connect( GTK_OBJECT(window), "key_press_event",
G_CALLBACK(key_press_event), &globals );
g_signal_connect( GTK_OBJECT(window), "key_release_event",
G_CALLBACK(key_release_event), &globals );

View file

@ -57,6 +57,7 @@ typedef struct GtkDrawCtx {
PangoLayout* layout[LAYOUT_NLAYOUTS];
XP_U16 trayOwner;
XP_Bool topFocus;
} GtkDrawCtx;
typedef struct ClientStreamRec {

View file

@ -286,6 +286,50 @@ usage( char* appName, char* msg )
exit(1);
} /* usage */
#ifdef KEYBOARD_NAV
XP_Bool
linShiftFocus( CommonGlobals* cGlobals, XP_Key key, const BoardObjectType* order,
BoardObjectType* nxtP )
{
BoardCtxt* board = cGlobals->game.board;
XP_Bool handled = XP_FALSE;
BoardObjectType nxt = OBJ_NONE;
BoardObjectType cur;
XP_U16 i, curIndex;
cur = board_getFocusOwner( board );
if ( cur == OBJ_NONE ) {
cur = order[0];
}
for ( i = 0; i < 3; ++i ) {
if ( cur == order[i] ) {
curIndex = i;
break;
}
}
XP_ASSERT( curIndex < 3 );
curIndex += 3;
if ( key == XP_CURSOR_KEY_DOWN || key == XP_CURSOR_KEY_RIGHT ) {
++curIndex;
} else if ( key == XP_CURSOR_KEY_UP || key == XP_CURSOR_KEY_LEFT ) {
--curIndex;
} else {
XP_ASSERT(0);
}
curIndex %= 3;
nxt = order[curIndex];
handled = board_focusChanged( board, nxt, XP_TRUE );
if ( !!nxtP ) {
*nxtP = nxt;
}
return handled;
} /* linShiftFocus */
#endif
#ifdef XWFEATURE_RELAY
static int
linux_init_relay_socket( CommonGlobals* cGlobals )

View file

@ -53,4 +53,10 @@ XP_UCHAR* strFromStream( XWStreamCtxt* stream );
void catGameHistory( CommonGlobals* cGlobals );
void catOnClose( XWStreamCtxt* stream, void* closure );
#ifdef KEYBOARD_NAV
XP_Bool linShiftFocus( CommonGlobals* cGlobals, XP_Key key,
const BoardObjectType* order,
BoardObjectType* nxtP );
#endif
#endif