gtk/ncurses support for Rem: focus and showing remaining tiles. Also

rewrite gtkask to use gtk_message_dialog and add sigint handler.
This commit is contained in:
ehouse 2008-10-24 09:07:30 +00:00
parent 3b5337d7d2
commit 9b17c20117
7 changed files with 116 additions and 115 deletions

View file

@ -141,13 +141,17 @@ curses_draw_measureRemText( DrawCtx* XP_UNUSED(dctx),
static void
curses_draw_drawRemText( DrawCtx* p_dctx, const XP_Rect* rInner,
const XP_Rect* XP_UNUSED(rOuter), XP_S16 nTilesLeft )
const XP_Rect* XP_UNUSED(rOuter), XP_S16 nTilesLeft,
XP_Bool focussed )
{
CursesDrawCtx* dctx = (CursesDrawCtx*)p_dctx;
char buf[32];
formatRemText( buf, sizeof(buf), nTilesLeft, rInner->width );
mvwprintw( dctx->boardWin, rInner->top, rInner->left, buf );
if ( focussed ) {
cursesHiliteRect( dctx->boardWin, rInner );
}
} /* curses_draw_drawRemText */
static int

View file

@ -1158,6 +1158,25 @@ curses_util_warnIllegalWord( XW_UtilCtxt* XP_UNUSED(uc),
return XP_FALSE;
} /* curses_util_warnIllegalWord */
static void
curses_util_remSelected( XW_UtilCtxt* uc )
{
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
XWStreamCtxt* stream;
XP_UCHAR* text;
stream = mem_stream_make( MPPARM(globals->cGlobals.params->util->mpool)
globals->cGlobals.params->vtMgr,
globals, CHANNEL_NONE, NULL );
board_formatRemainingTiles( globals->cGlobals.game.board, stream );
text = strFromStream( stream );
(void)cursesask( globals, text, 1, "Ok" );
free( text );
}
#ifndef XWFEATURE_STANDALONE_ONLY
static void
cursesSendOnClose( XWStreamCtxt* stream, void* closure )
@ -1192,6 +1211,7 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_askPassword = curses_util_askPassword;
util->vtable->m_util_yOffsetChange = curses_util_yOffsetChange;
util->vtable->m_util_warnIllegalWord = curses_util_warnIllegalWord;
util->vtable->m_util_remSelected = curses_util_remSelected;
#ifndef XWFEATURE_STANDALONE_ONLY
util->vtable->m_util_makeStreamFromAddr = curses_util_makeStreamFromAddr;
#endif

View file

@ -1,4 +1,5 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/* -*-mode: C; fill-column: 78; compile-command: "make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2000 by Eric House (xwords@eehouse.org). All rights reserved.
*
@ -22,61 +23,16 @@
#include "gtkask.h"
static void
button_event( GtkWidget* XP_UNUSED(widget), void* closure )
XP_Bool
gtkask( const gchar *message, GtkButtonsType buttons )
{
gboolean* whichSet = (gboolean*)closure;
*whichSet = 1;
gtk_main_quit();
}
gint
gtkask( gchar *message, gint numButtons, char* button1, ... )
{
GtkWidget* dialog;
GtkWidget* label;
GtkWidget* button;
short i;
gboolean* results = g_malloc( numButtons * sizeof(results[0]) );
char** butList = &button1;
/* Create the widgets */
dialog = gtk_dialog_new();
gtk_window_set_modal( GTK_WINDOW( dialog ), TRUE );
label = gtk_label_new( message );
for ( i = 0; i < numButtons; ++i ) {
button = gtk_button_new_with_label( *butList );
results[i] = 0;
g_signal_connect( GTK_OBJECT( button ), "clicked",
G_CALLBACK(button_event), &results[i] );
gtk_container_add( GTK_CONTAINER( GTK_DIALOG(dialog)->action_area),
button );
++butList;
}
/* Add the label, and show everything we've added to the dialog. */
gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
label);
gtk_widget_show_all (dialog);
/* returns when button handler calls gtk_main_quit */
gtk_main();
gtk_widget_destroy( dialog );
for ( i = 0; i < numButtons; ++i ) {
if ( results[i] ) {
break;
}
}
g_free( results );
return i;
GtkWidget* dlg = gtk_message_dialog_new( NULL, /* parent */
GTK_MESSAGE_QUESTION,
GTK_DIALOG_MODAL,
buttons, message );
gint response = gtk_dialog_run( GTK_DIALOG(dlg) );
gtk_widget_destroy( dlg );
return response == GTK_RESPONSE_OK || response == GTK_RESPONSE_YES;
} /* gtkask */
#endif

View file

@ -25,7 +25,9 @@
#include "gtkmain.h"
gint gtkask( gchar *message, gint numButtons, char* button1, ... );
/* Returns true for "yes" or "ok" answer, false otherwise.
*/
XP_Bool gtkask( const gchar *message, GtkButtonsType buttons );
#endif
#endif /* PLATFORM_GTK */

View file

@ -63,7 +63,7 @@ gtkInsetRect( XP_Rect* r, short i )
#define GTKMIN_W_HT 12
static void
gtkFillRect( GtkDrawCtx* dctx, const XP_Rect* rect, GdkColor* color )
gtkFillRect( GtkDrawCtx* dctx, const XP_Rect* rect, const GdkColor* color )
{
gdk_gc_set_foreground( dctx->drawGC, color );
gdk_draw_rectangle( DRAW_WHAT(dctx), dctx->drawGC,
@ -190,15 +190,17 @@ layout_for_ht( GtkDrawCtx* dctx, XP_U16 ht )
} /* layout_for_ht */
static void
draw_string_at( GtkDrawCtx* dctx, const char* str, XP_U16 fontHt,
draw_string_at( GtkDrawCtx* dctx, PangoLayout* layout,
const char* str, XP_U16 fontHt,
const XP_Rect* where, XP_GTK_JUST just,
const GdkColor* frground, const GdkColor* bkgrnd )
{
PangoLayout* layout;
gint xx = where->left;
gint yy = where->top;
layout = layout_for_ht( dctx, fontHt );
if ( !layout ) {
layout = layout_for_ht( dctx, fontHt );
}
pango_layout_set_text( layout, str, strlen(str) );
@ -463,8 +465,8 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
}
}
if ( (flags & CELL_ISSTAR) != 0 ) {
draw_string_at( dctx, "*", rect->height, rect, XP_GTK_JUST_CENTER,
&dctx->black, NULL );
draw_string_at( dctx, NULL, "*", rect->height, rect,
XP_GTK_JUST_CENTER, &dctx->black, NULL );
}
} else if ( !!letter ) {
GdkColor* foreground;
@ -478,7 +480,7 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
rectInset.width+1, rectInset.height+1 );
foreground = highlight? &dctx->white : &dctx->playerColors[owner];
draw_string_at( dctx, letter, rectInset.height-2, &rectInset,
draw_string_at( dctx, NULL, letter, rectInset.height-2, &rectInset,
XP_GTK_JUST_CENTER, foreground, cursor );
if ( (flags & CELL_ISBLANK) != 0 ) {
@ -561,7 +563,7 @@ gtkDrawTileImpl( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
if ( !!textP ) {
if ( *textP != LETTER_NONE ) { /* blank */
draw_string_at( dctx, textP, formatRect.height>>1,
draw_string_at( dctx, NULL, textP, formatRect.height>>1,
&formatRect, XP_GTK_JUST_TOPLEFT,
foreground, NULL );
@ -573,7 +575,7 @@ gtkDrawTileImpl( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* textP,
sprintf( numbuf, "%d", val );
len = strlen( numbuf );
draw_string_at( dctx, numbuf, formatRect.height>>2,
draw_string_at( dctx, NULL, numbuf, formatRect.height>>2,
&formatRect, XP_GTK_JUST_BOTTOMRIGHT,
foreground, NULL );
@ -631,7 +633,7 @@ gtk_draw_drawTileBack( DrawCtx* p_dctx, const XP_Rect* rect,
gtkInsetRect( &r, 1 );
gtkFillRect( dctx, &r, hasCursor? &dctx->cursor : &dctx->tileBack );
draw_string_at( dctx, "?", r.height,
draw_string_at( dctx, NULL, "?", r.height,
&r, XP_GTK_JUST_CENTER,
&dctx->playerColors[dctx->trayOwner], NULL );
@ -686,7 +688,7 @@ gtk_draw_drawBoardArrow( DrawCtx* p_dctx, const XP_Rect* rectP,
const char* curs = vertical? "|":"-";
/* font needs to be small enough that "|" doesn't overwrite cell below */
draw_string_at( dctx, curs, (rectP->height*2)/3,
draw_string_at( dctx, NULL, curs, (rectP->height*2)/3,
rectP, XP_GTK_JUST_CENTER,
&dctx->black, NULL );
drawHintBorders( dctx, rectP, hintAtts );
@ -733,16 +735,17 @@ getLayoutToFitRect( GtkDrawCtx* dctx, const char* str, const XP_Rect* rect )
static void
gtkDrawDrawRemText( DrawCtx* p_dctx, const XP_Rect* rect, XP_S16 nTilesLeft,
XP_U16* widthP, XP_U16* heightP )
XP_U16* widthP, XP_U16* heightP, XP_Bool focussed )
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
char buf[10];
PangoLayout* layout;
snprintf( buf, sizeof(buf), "rem:%d", nTilesLeft );
layout = getLayoutToFitRect( dctx, buf, rect );
if ( !!widthP ) {
int width, height;
PangoLayout* layout = getLayoutToFitRect( dctx, buf, rect );
pango_layout_get_pixel_size( layout, &width, &height );
if ( width > rect->width ) {
width = rect->width;
@ -753,24 +756,34 @@ gtkDrawDrawRemText( DrawCtx* p_dctx, const XP_Rect* rect, XP_S16 nTilesLeft,
*widthP = width;
*heightP = height;
} else {
draw_string_at( dctx, buf, rect->height,
const GdkColor* cursor = NULL;
if ( focussed ) {
cursor = &dctx->cursor;
gtkFillRect( dctx, rect, cursor );
}
draw_string_at( dctx, layout, buf, rect->height,
rect, XP_GTK_JUST_TOPLEFT,
&dctx->black, NULL );
&dctx->black, cursor );
}
} /* gtkDrawDrawRemText */
static void
gtk_draw_measureRemText( DrawCtx* p_dctx, const XP_Rect* r, XP_S16 nTilesLeft,
gtk_draw_measureRemText( DrawCtx* p_dctx, const XP_Rect* rect, XP_S16 nTilesLeft,
XP_U16* width, XP_U16* height )
{
gtkDrawDrawRemText( p_dctx, r, nTilesLeft, width, height );
if ( nTilesLeft <= 0 ) {
*width = *height = 0;
} else {
gtkDrawDrawRemText( p_dctx, rect, nTilesLeft, width, height, XP_FALSE );
}
} /* gtk_draw_measureRemText */
static void
gtk_draw_drawRemText( DrawCtx* p_dctx, const XP_Rect* rInner,
const XP_Rect* XP_UNUSED(rOuter), XP_S16 nTilesLeft )
const XP_Rect* XP_UNUSED(rOuter), XP_S16 nTilesLeft,
XP_Bool focussed )
{
gtkDrawDrawRemText( p_dctx, rInner, nTilesLeft, NULL, NULL );
gtkDrawDrawRemText( p_dctx, rInner, nTilesLeft, NULL, NULL, focussed );
} /* gtk_draw_drawRemText */
static void
@ -844,7 +857,7 @@ gtk_draw_score_drawPlayer( DrawCtx* p_dctx, const XP_Rect* rInner,
gtkEraseRect( dctx, rInner );
}
draw_string_at( dctx, scoreBuf, rInner->height - 1,
draw_string_at( dctx, NULL, scoreBuf, rInner->height - 1,
rInner, XP_GTK_JUST_CENTER,
&dctx->playerColors[dsi->playerNum], cursor );
@ -880,10 +893,10 @@ gtk_draw_score_pendingScore( DrawCtx* p_dctx, const XP_Rect* rect,
}
ht = localR.height >> 2;
draw_string_at( dctx, "Pts:", ht,
draw_string_at( dctx, NULL, "Pts:", ht,
&localR, XP_GTK_JUST_TOPLEFT,
&dctx->black, cursor );
draw_string_at( dctx, buf, ht,
draw_string_at( dctx, NULL, buf, ht,
&localR, XP_GTK_JUST_BOTTOMRIGHT,
&dctx->black, cursor );
@ -916,7 +929,7 @@ gtk_draw_drawTimer( DrawCtx* p_dctx, const XP_Rect* rInner,
/* gdk_gc_set_clip_rectangle( dctx->drawGC, (GdkRectangle*)rInner ); */
gtkEraseRect( dctx, rInner );
draw_string_at( dctx, buf, rInner->height-1,
draw_string_at( dctx, NULL, buf, rInner->height-1,
rInner, XP_GTK_JUST_CENTER,
&dctx->black, NULL );
} /* gtk_draw_drawTimer */
@ -986,7 +999,7 @@ gtk_draw_drawMiniWindow( DrawCtx* p_dctx, const XP_UCHAR* text,
gtkEraseRect( dctx, &localR );
frameRect( dctx, &localR );
draw_string_at( dctx, text, GTKMIN_W_HT,
draw_string_at( dctx, NULL, text, GTKMIN_W_HT,
&localR, XP_GTK_JUST_CENTER,
&dctx->black, NULL );
} /* gtk_draw_drawMiniWindow */

View file

@ -32,6 +32,8 @@
#include <ctype.h>
#include <gdk/gdkkeysyms.h>
#include <errno.h>
#include <signal.h>
#ifndef CLIENT_ONLY
/* # include <prc.h> */
#endif
@ -605,12 +607,8 @@ final_scores( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
if ( gameOver ) {
printFinalScores( globals );
} else {
XP_Bool confirmed;
confirmed =
gtkask( "Are you sure everybody wants to end the game now?",
2, "Yes", "No" ) == 0;
if ( confirmed ) {
if ( gtkask( "Are you sure everybody wants to end the game now?",
GTK_BUTTONS_YES_NO ) ) {
server_endGame( globals->cGlobals.game.server );
gameOver = TRUE;
}
@ -1022,7 +1020,7 @@ gtkUserError( GtkAppGlobals* XP_UNUSED(globals), const char* format, ... )
vsprintf( buf, format, ap );
(void)gtkask( buf, 1, "OK" );
(void)gtkask( buf, GTK_BUTTONS_OK );
va_end(ap);
} /* gtkUserError */
@ -1327,12 +1325,30 @@ gtk_util_warnIllegalWord( XW_UtilCtxt* uc, BadWordInfo* bwi, XP_U16 player,
XP_ASSERT( bwi->nWords == 1 );
sprintf( buf, "Word \"%s\" not in the current dictionary. "
"Use it anyway?", bwi->words[0] );
result = 0 == gtkask( buf, 2, "Ok", "Cancel" );
result = gtkask( buf, GTK_BUTTONS_YES_NO );
}
return result;
} /* gtk_util_warnIllegalWord */
static void
gtk_util_remSelected( XW_UtilCtxt* uc )
{
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
XWStreamCtxt* stream;
XP_UCHAR* text;
stream = mem_stream_make( MEMPOOL
globals->cGlobals.params->vtMgr,
globals, CHANNEL_NONE, NULL );
board_formatRemainingTiles( globals->cGlobals.game.board, stream );
text = strFromStream( stream );
stream_destroy( stream );
(void)gtkask( text, GTK_BUTTONS_OK );
free( text );
}
#ifndef XWFEATURE_STANDALONE_ONLY
static XWStreamCtxt*
gtk_util_makeStreamFromAddr(XW_UtilCtxt* uc, XP_PlayerAddr channelNo )
@ -1380,34 +1396,23 @@ gtk_util_userQuery( XW_UtilCtxt* XP_UNUSED(uc), UtilQueryID id,
{
XP_Bool result;
char* question;
char* answers[3];
gint numAnswers = 0;
XP_U16 okIndex = 1;
XP_Bool freeMe = XP_FALSE;
GtkButtonsType buttons = GTK_BUTTONS_YES_NO;
switch( id ) {
case QUERY_COMMIT_TURN:
question = strFromStream( stream );
freeMe = XP_TRUE;
/* len = stream_getSize( stream ); */
/* question = malloc( len + 1 ); */
/* stream_getBytes( stream, question, len ); */
/* question[len] = '\0'; */
answers[numAnswers++] = "Cancel";
answers[numAnswers++] = "Ok";
break;
case QUERY_COMMIT_TRADE:
question = "Are you sure you want to trade the selected tiles?";
answers[numAnswers++] = "Cancel";
answers[numAnswers++] = "Ok";
break;
case QUERY_ROBOT_MOVE:
case QUERY_ROBOT_TRADE:
question = strFromStream( stream );
freeMe = XP_TRUE;
answers[numAnswers++] = "Ok";
okIndex = 0;
buttons = GTK_BUTTONS_OK;
break;
default:
@ -1415,8 +1420,7 @@ gtk_util_userQuery( XW_UtilCtxt* XP_UNUSED(uc), UtilQueryID id,
return XP_FALSE;
}
result = gtkask( question, numAnswers,
answers[0], answers[1], answers[2] ) == okIndex;
result = gtkask( question, buttons );
if ( freeMe > 0 ) {
free( question );
@ -1553,6 +1557,7 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_setTimer = gtk_util_setTimer;
util->vtable->m_util_requestTime = gtk_util_requestTime;
util->vtable->m_util_warnIllegalWord = gtk_util_warnIllegalWord;
util->vtable->m_util_remSelected = gtk_util_remSelected;
#ifndef XWFEATURE_STANDALONE_ONLY
util->vtable->m_util_makeStreamFromAddr = gtk_util_makeStreamFromAddr;
#endif
@ -1778,6 +1783,13 @@ drop_msg_toggle( GtkWidget* toggle, GtkAppGlobals* globals )
} /* drop_msg_toggle */
#endif
static GtkAppGlobals* g_globals_for_signal;
static void
handle_sigint( int XP_UNUSED(sig) )
{
quit( NULL, g_globals_for_signal );
}
int
gtkmain( LaunchParams* params, int argc, char *argv[] )
{
@ -1793,6 +1805,10 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
GtkWidget* dropCheck;
#endif
g_globals_for_signal = &globals;
struct sigaction act = { .sa_handler = handle_sigint };
sigaction( SIGINT, &act, NULL );
memset( &globals, 0, sizeof(globals) );
globals.cGlobals.params = params;
@ -1812,16 +1828,6 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
setupGtkUtilCallbacks( &globals, params->util );
/* globals.dictionary = params->dict; */
/* globals.trayOverlaps = params->trayOverlaps; */
/* globals.askNewGame = params->askNewGame; */
/* globals.quitWhenDone = params->quitAfter; */
/* globals.sleepOnAnchor = params->sleepOnAnchor; */
/* globals.util = params->util; */
/* globals.fileName = params->fileName; */
/* globals.listenPort = params->listenPort; */
/* Now set up the gtk stuff. This is necessary before we make the
draw ctxt */
gtk_init( &argc, &argv );

View file

@ -383,7 +383,7 @@ gtk_newgame_col_enable( void* closure, XP_U16 player, NewGameColumn col,
gtk_widget_set_sensitive( widget, enable == TRI_ENAB_ENABLED );
if ( !!label ) {
gtk_widget_show( label );
gtk_widget_set_sensitive( label, enable == TRI_ENAB_ENABLED );
gtk_widget_set_sensitive( label, enable == TRI_ENAB_ENABLED );
}
}
} /* gtk_newgame_col_enable */