From 6a5454ad7461311dd7b7ad5590bd94a494affb9d Mon Sep 17 00:00:00 2001 From: ehouse Date: Fri, 24 Oct 2008 09:07:30 +0000 Subject: [PATCH] gtk/ncurses support for Rem: focus and showing remaining tiles. Also rewrite gtkask to use gtk_message_dialog and add sigint handler. --- linux/cursesdraw.c | 6 +++- linux/cursesmain.c | 20 +++++++++++++ linux/gtkask.c | 66 +++++++----------------------------------- linux/gtkask.h | 4 ++- linux/gtkdraw.c | 61 +++++++++++++++++++++++---------------- linux/gtkmain.c | 72 +++++++++++++++++++++++++--------------------- linux/gtknewgame.c | 2 +- 7 files changed, 116 insertions(+), 115 deletions(-) diff --git a/linux/cursesdraw.c b/linux/cursesdraw.c index 62addde8b..da3d4985e 100644 --- a/linux/cursesdraw.c +++ b/linux/cursesdraw.c @@ -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 diff --git a/linux/cursesmain.c b/linux/cursesmain.c index 2821788f3..b46ccfa4d 100644 --- a/linux/cursesmain.c +++ b/linux/cursesmain.c @@ -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 diff --git a/linux/gtkask.c b/linux/gtkask.c index 66d1c6285..6a60978de 100644 --- a/linux/gtkask.c +++ b/linux/gtkask.c @@ -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 diff --git a/linux/gtkask.h b/linux/gtkask.h index 003d32371..dfc2ced75 100644 --- a/linux/gtkask.h +++ b/linux/gtkask.h @@ -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 */ diff --git a/linux/gtkdraw.c b/linux/gtkdraw.c index f16319bb0..fb819f00b 100644 --- a/linux/gtkdraw.c +++ b/linux/gtkdraw.c @@ -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 */ diff --git a/linux/gtkmain.c b/linux/gtkmain.c index c812e9f63..02510a81f 100644 --- a/linux/gtkmain.c +++ b/linux/gtkmain.c @@ -32,6 +32,8 @@ #include #include #include +#include + #ifndef CLIENT_ONLY /* # include */ #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 ); diff --git a/linux/gtknewgame.c b/linux/gtknewgame.c index 80f647fe9..c1f8f8587 100644 --- a/linux/gtknewgame.c +++ b/linux/gtknewgame.c @@ -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 */