make alert and confirm non-blocking

Using a custom div and callbacks. TODO: make it floating so it's more
dialog-like. But that's just css at this point.
This commit is contained in:
Eric House 2021-02-13 10:37:47 -08:00
parent 76139c43f6
commit eec86e099d
4 changed files with 120 additions and 15 deletions

View file

@ -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 $@

View file

@ -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 )
{

View file

@ -45,6 +45,9 @@
to {transform: rotate(360deg);}
}
#nbalert {
}
</style>
</head>
<body class="centered">
@ -54,6 +57,7 @@
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div id='nbalert'></div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
</div>

View file

@ -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