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; XP_Bool handled;
checkAssignFocus( globals->cGlobals.game.board ); checkAssignFocus( globals->cGlobals.game.board );
globals->doDraw = board_handleKey( globals->cGlobals.game.board, globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
XP_RAISEFOCUS_KEY, &handled ); XP_RAISEFOCUS_KEY, &handled );
return XP_TRUE; return XP_TRUE;
} /* handleSpace */ } /* handleSpace */
@ -349,8 +349,8 @@ static XP_Bool
handleRet( CursesAppGlobals* globals ) handleRet( CursesAppGlobals* globals )
{ {
XP_Bool handled; XP_Bool handled;
globals->doDraw = board_handleKey( globals->cGlobals.game.board, globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
XP_RETURN_KEY, &handled ); XP_RETURN_KEY, &handled );
return XP_TRUE; return XP_TRUE;
} /* handleRet */ } /* handleRet */
@ -437,8 +437,8 @@ static XP_Bool
handleBackspace( CursesAppGlobals* globals ) handleBackspace( CursesAppGlobals* globals )
{ {
XP_Bool handled; XP_Bool handled;
globals->doDraw = board_handleKey( globals->cGlobals.game.board, globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
XP_CURSOR_KEY_DEL, &handled ); XP_CURSOR_KEY_DEL, &handled );
return XP_TRUE; return XP_TRUE;
} /* handleBackspace */ } /* handleBackspace */
@ -482,46 +482,6 @@ MenuList sharedMenuList[] = {
}; };
#ifdef KEYBOARD_NAV #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 static XP_Bool
handleFocusKey( CursesAppGlobals* globals, XP_Key key ) handleFocusKey( CursesAppGlobals* globals, XP_Key key )
{ {
@ -530,9 +490,14 @@ handleFocusKey( CursesAppGlobals* globals, XP_Key key )
checkAssignFocus( globals->cGlobals.game.board ); 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 ) { 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; globals->doDraw = draw || globals->doDraw;
@ -1037,8 +1002,8 @@ passKeyToBoard( CursesAppGlobals* globals, char ch )
XP_Bool handled = ch >= 'a' && ch <= 'z'; XP_Bool handled = ch >= 'a' && ch <= 'z';
if ( handled ) { if ( handled ) {
ch += 'A' - 'a'; ch += 'A' - 'a';
globals->doDraw = board_handleKey( globals->cGlobals.game.board, globals->doDraw = board_handleKeyUp( globals->cGlobals.game.board,
ch, NULL ); ch, NULL );
} }
return handled; return handled;
} /* passKeyToBoard */ } /* 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * 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 */ } /* draw_finish */
static void static void
gtk_draw_objFinished( DrawCtx* XP_UNUSED(p_dctx), drawFocusFrame( GtkDrawCtx* dctx, const XP_Rect* r )
BoardObjectType XP_UNUSED(typ),
const XP_Rect* XP_UNUSED(rect),
DrawFocusState XP_UNUSED(dfs) )
{ {
// 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 */ } /* draw_finished */
static void static void
@ -378,6 +404,10 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
drawHintBorders( dctx, rect, hintAtts ); drawHintBorders( dctx, rect, hintAtts );
if ( (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
return XP_TRUE; return XP_TRUE;
} /* gtk_draw_drawCell */ } /* gtk_draw_drawCell */
@ -404,12 +434,14 @@ gtk_draw_invertCell( DrawCtx* XP_UNUSED(p_dctx),
static XP_Bool static XP_Bool
gtk_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 owner, gtk_draw_trayBegin( DrawCtx* p_dctx, const XP_Rect* rect, XP_U16 owner,
DrawFocusState XP_UNUSED(dfs) ) DrawFocusState dfs )
{ {
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect clip = *rect; XP_Rect clip = *rect;
insetRect( &clip, -1 ); insetRect( &clip, -1 );
dctx->trayOwner = owner; dctx->trayOwner = owner;
dctx->topFocus = dfs == DFS_TOP;
/* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)&clip ); */ /* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)&clip ); */
return XP_TRUE; return XP_TRUE;
} /* gtk_draw_trayBegin */ } /* 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); insetR.width, insetR.height);
} }
} }
if ( !dctx->topFocus && (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
} /* gtk_draw_drawTile */ } /* gtk_draw_drawTile */
static void static void
gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect, gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect,
CellFlags XP_UNUSED(flags) ) CellFlags flags )
{ {
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect r = *rect; 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], "?", draw_string_at( dctx, dctx->layout[LAYOUT_LARGE], "?",
&r, XP_GTK_JUST_CENTER, &r, XP_GTK_JUST_CENTER,
&dctx->playerColors[dctx->trayOwner], NULL ); &dctx->playerColors[dctx->trayOwner], NULL );
if ( !dctx->topFocus && (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
} /* gtk_draw_drawTileBack */ } /* gtk_draw_drawTileBack */
static void static void
@ -577,12 +618,13 @@ gtk_draw_drawBoardArrow( DrawCtx* p_dctx, const XP_Rect* rectP,
static void static void
gtk_draw_scoreBegin( DrawCtx* p_dctx, const XP_Rect* rect, gtk_draw_scoreBegin( DrawCtx* p_dctx, const XP_Rect* rect,
XP_U16 XP_UNUSED(numPlayers), XP_U16 XP_UNUSED(numPlayers),
DrawFocusState XP_UNUSED(dfs) ) DrawFocusState dfs )
{ {
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
/* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)rect ); */ /* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)rect ); */
eraseRect( dctx, rect ); eraseRect( dctx, rect );
dctx->topFocus = dfs == DFS_TOP;
} /* gtk_draw_scoreBegin */ } /* gtk_draw_scoreBegin */
static void 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, draw_string_at( dctx, dctx->layout[LAYOUT_SMALL], scoreBuf,
rInner, XP_GTK_JUST_CENTER, rInner, XP_GTK_JUST_CENTER,
&dctx->playerColors[dsi->playerNum], NULL ); &dctx->playerColors[dsi->playerNum], NULL );
if ( !dctx->topFocus && ((dsi->flags & CELL_ISCURSOR) != 0) ) {
drawFocusFrame( dctx, rOuter );
}
} /* gtk_draw_score_drawPlayer */ } /* gtk_draw_score_drawPlayer */
static void static void
gtk_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect, gtk_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect,
XP_S16 score, XP_U16 XP_UNUSED(playerNum), XP_S16 score, XP_U16 XP_UNUSED(playerNum),
CellFlags XP_UNUSED(flags) ) CellFlags flags )
{ {
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx; GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
char buf[5]; 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, draw_string_at( dctx, dctx->layout[LAYOUT_SMALL], buf,
&localR, XP_GTK_JUST_BOTTOMRIGHT, &localR, XP_GTK_JUST_BOTTOMRIGHT,
&dctx->black, NULL ); &dctx->black, NULL );
if ( !dctx->topFocus && (flags & CELL_ISCURSOR) != 0 ) {
drawFocusFrame( dctx, rect );
}
} /* gtk_draw_score_pendingScore */ } /* gtk_draw_score_pendingScore */
static void static void

View file

@ -153,17 +153,20 @@ button_release_event( GtkWidget* XP_UNUSED(widget), GdkEventMotion *event,
return 1; return 1;
} /* button_release_event */ } /* button_release_event */
static gint static XP_Key
key_release_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event, evtToXPKey( GdkEventKey* event, XP_Bool* movesCursorP )
GtkAppGlobals* globals )
{ {
XP_Key xpkey = XP_KEY_NONE; XP_Key xpkey = XP_KEY_NONE;
XP_Bool movesCursor = XP_FALSE; XP_Bool movesCursor = XP_FALSE;
guint keyval = event->keyval; guint keyval = event->keyval;
XP_LOGF( "got key 0x%x", keyval ); switch( keyval ) {
case GDK_Return:
switch( keyval ) { xpkey = XP_RETURN_KEY;
break;
case GDK_space:
xpkey = XP_RAISEFOCUS_KEY;
break;
case GDK_Left: case GDK_Left:
xpkey = XP_CURSOR_KEY_LEFT; xpkey = XP_CURSOR_KEY_LEFT;
@ -191,16 +194,43 @@ key_release_event( GtkWidget* XP_UNUSED(widget), GdkEventKey* event,
xpkey = toupper(keyval); xpkey = toupper(keyval);
break; 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 ) { if ( xpkey != XP_KEY_NONE ) {
XP_Bool handled;
XP_Bool draw; XP_Bool draw;
draw = board_handleKey( globals->cGlobals.game.board, xpkey, &handled ); draw = board_handleKeyUp( globals->cGlobals.game.board, xpkey, &handled );
if ( movesCursor || !handled ) { if ( movesCursor && !handled ) {
XP_LOGF( "need to handle focus shift" ); BoardObjectType order[] = { OBJ_SCORE, OBJ_BOARD, OBJ_TRAY };
draw = linShiftFocus( &globals->cGlobals, xpkey, order,
NULL ) || draw;
} }
if ( 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 */ } /* key_release_event */
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
@ -1134,7 +1164,7 @@ pentimer_idle_func( gpointer data )
GtkAppGlobals* globals = (GtkAppGlobals*)data; GtkAppGlobals* globals = (GtkAppGlobals*)data;
struct timeval tv; struct timeval tv;
XP_Bool callAgain = XP_TRUE; XP_Bool callAgain = XP_TRUE;
gettimeofday( &tv, NULL ); gettimeofday( &tv, NULL );
if ( (tv.tv_usec - globals->penTv.tv_usec) >= globals->penTimerInterval) { 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_signal_connect( GTK_OBJECT(drawing_area), "button_release_event",
G_CALLBACK(button_release_event), &globals ); 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_signal_connect( GTK_OBJECT(window), "key_release_event",
G_CALLBACK(key_release_event), &globals ); G_CALLBACK(key_release_event), &globals );

View file

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

View file

@ -286,6 +286,50 @@ usage( char* appName, char* msg )
exit(1); exit(1);
} /* usage */ } /* 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 #ifdef XWFEATURE_RELAY
static int static int
linux_init_relay_socket( CommonGlobals* cGlobals ) linux_init_relay_socket( CommonGlobals* cGlobals )

View file

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