diff --git a/xwords4/wasm/Makefile b/xwords4/wasm/Makefile index b88ca348e..12ca2380e 100644 --- a/xwords4/wasm/Makefile +++ b/xwords4/wasm/Makefile @@ -72,7 +72,7 @@ main.html: ${INPUTS} $(MAKEFILE) shell_minimal.html --preload-file assets_dir --shell-file shell_minimal.html \ -s USE_SDL_TTF=2 -s USE_SDL_IMAGE=2 -s SDL2_IMAGE_FORMATS='["png"]' \ -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" \ - -s EXPORTED_FUNCTIONS='["_main", "_button", "_newgame", "_gotMQTTMsg", "_jscallback"]' \ + -s EXPORTED_FUNCTIONS='["_main", "_button", "_newgame", "_gotMQTTMsg", "_jscallback", "_onDlgButton"]' \ -s WASM=1 \ ${INPUTS} -o $@ diff --git a/xwords4/wasm/main.c b/xwords4/wasm/main.c index 24d74d300..09e60c2a2 100644 --- a/xwords4/wasm/main.c +++ b/xwords4/wasm/main.c @@ -54,12 +54,30 @@ #define KEY_GAME "the_game" #define DICTNAME "assets_dir/CollegeEng_2to8.xwd" -EM_JS(bool, call_confirm, (const char* str), { - return confirm(UTF8ToString(str)); -}); -EM_JS(void, call_alert, (const char* str), { - alert(UTF8ToString(str)); -}); +#define BUTTON_OK "OK" +#define BUTTON_CANCEL "Cancel" + +typedef void (*AlertProc)(void* closure, const char* button); + +/* typedef struct _Buttons { */ +/* int nButtons; */ +/* const char** buttons; */ +/* } Buttons; */ + +EM_JS(void, call_dialog, (const char* str, const char** but_strs, + AlertProc proc, void* closure), { + var buttons = []; + for ( let ii = 0; ii < 3; ++ii ) { + const mem = HEAP32[(but_strs + (ii * 4)) >> 2]; + if ( 0 == mem ) { + break; + } + const str = UTF8ToString(mem); + buttons.push(str); + } + nbDialog(UTF8ToString(str), buttons, proc, closure); + } ); + EM_JS(void, call_haveDevID, (void* closure, const char* devid), { onHaveDevID(closure, UTF8ToString(devid)); }); @@ -87,6 +105,13 @@ EM_JS(void, setButtonText, (const char* id, const char* text), { static void updateScreen( Globals* globals, bool doSave ); +static void +call_alert( const char* msg ) +{ + const char* buttons[] = { BUTTON_OK, NULL }; + call_dialog( msg, buttons, NULL, NULL ); +} + static XP_S16 send_msg( XWEnv xwe, const XP_U8* buf, XP_U16 len, const XP_UCHAR* msgNo, const CommsAddrRec* addr, @@ -203,8 +228,9 @@ gameFromInvite( Globals* globals, const NetLaunchInfo* invite ) if ( globals->gi.gameID == invite->gameID ) { XP_LOGFF( "duplicate invite; ignoring" ); needsLoad = false; - } else if ( ! call_confirm( "Invitation received; replace current game?" ) ) { - needsLoad = false; + } else { + call_alert( "Invitation received; replace current game?" ); + // needsLoad = false; } } else if ( invite->lang != 1 ) { call_alert( "Invitations are only supported for play in English right now." ); @@ -425,12 +451,32 @@ main_set_timer( Globals* globals, XWTimerReason why, XP_U16 when, jscallback_set( onTimerFired, tc, when ); } +typedef struct _QueryState { + Globals* globals; + QueryProc proc; + void* closure; +} QueryState; + +static void +onQueryCalled( void* closure, const char* button ) +{ + QueryState* qs = (QueryState*)closure; + bool ok = 0 == strcmp( button, BUTTON_OK ); + (*qs->proc)( qs->closure, ok ); + updateTradeButton( qs->globals ); + XP_FREE( qs->globals->mpool, qs ); +} + void main_query( Globals* globals, const XP_UCHAR* query, QueryProc proc, void* closure ) { - bool ok = call_confirm( query ); - (*proc)( closure, ok ); - updateTradeButton( globals ); + QueryState* qs = XP_MALLOC( globals->mpool, sizeof(*qs) ); + qs->proc = proc; + qs->closure = closure; + qs->globals = globals; + + const char* buttons[] = { BUTTON_CANCEL, BUTTON_OK, NULL }; + call_dialog( query, buttons, onQueryCalled, qs ); } void @@ -668,14 +714,35 @@ initNoReturn( int argc, const char** argv ) emscripten_set_main_loop_arg( looper, globals, -1, 1 ); } +typedef struct _NewgameState { + Globals* globals; + bool p0; + bool p1; +} NewgameState; + +static void +onNewgameResponse( void* closure, const char* button ) +{ + NewgameState* ngs = (NewgameState*)closure; + Globals* globals = ngs->globals; + if ( 0 == strcmp( button, BUTTON_OK ) ) { + loadAndDraw( ngs->globals, NULL, true, ngs->p0, ngs->p1 ); + } + XP_FREE( globals->mpool, ngs ); +} + void newgame( void* closure, bool p0, bool p1 ) { Globals* globals = (Globals*)closure; + NewgameState* ngs = XP_MALLOC( globals->mpool, sizeof(*ngs) ); + ngs->globals = globals; + ngs->p0 = p0; + ngs->p1 = p1; XP_LOGFF( "(args: %d,%d)", p0, p1 ); - if ( call_confirm("Are you sure you want to replace the current game?") ) { - loadAndDraw( globals, NULL, true, p0, p1 ); - } + const char* query = "Are you sure you want to replace the current game?"; + const char* buttons[] = { BUTTON_CANCEL, BUTTON_OK, NULL }; + call_dialog( query, buttons, onNewgameResponse, ngs ); } void @@ -692,6 +759,14 @@ jscallback( JSCallback proc, void* closure ) (*proc)(closure); } +void +onDlgButton( AlertProc proc, void* closure, const char* button ) +{ + if ( !!proc ) { + (*proc)( closure, button ); + } +} + int main( int argc, const char** argv ) { diff --git a/xwords4/wasm/shell_minimal.html b/xwords4/wasm/shell_minimal.html index 8e6719e5c..77d94dcac 100644 --- a/xwords4/wasm/shell_minimal.html +++ b/xwords4/wasm/shell_minimal.html @@ -45,6 +45,9 @@ to {transform: rotate(360deg);} } + #nbalert { + } + @@ -54,6 +57,7 @@
+
diff --git a/xwords4/wasm/xwutils.js b/xwords4/wasm/xwutils.js index 12a8066f8..74806e4f7 100644 --- a/xwords4/wasm/xwutils.js +++ b/xwords4/wasm/xwutils.js @@ -75,6 +75,32 @@ function mqttSend( topic, ptr ) { return canSend; } +function nbDialog(msg, buttons, proc, closure) { + let dlg = document.getElementById('nbalert'); + while (dlg.firstChild) { + dlg.removeChild(dlg.firstChild); + } + + let txtDiv = document.createElement('div'); + txtDiv.textContent = msg + dlg.appendChild( txtDiv ); + + let span = document.createElement('div'); + for ( let buttonTxt of buttons ) { + let button = document.createElement('button'); + button.textContent = buttonTxt; + button.onclick = function() { + Module.ccall('onDlgButton', null, ['number', 'number', 'string'], + [proc, closure, buttonTxt]); + dlg.style.display = 'none'; // hide + }; + span.appendChild( button ); + } + dlg.appendChild( span ); + + dlg.style.display = 'block'; // reveal +} + for ( let one of ['paho-mqtt.js'] ) { let script = document.createElement('script'); script.src = one