aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/platforms/emscripten.cmake2
-rw-r--r--emcc.c84
-rw-r--r--emcclib.js23
-rw-r--r--emccpre.js12
-rwxr-xr-xhtml/jspage.pl1
-rw-r--r--puzzles.but8
6 files changed, 124 insertions, 6 deletions
diff --git a/cmake/platforms/emscripten.cmake b/cmake/platforms/emscripten.cmake
index c84a3c7..d74217f 100644
--- a/cmake/platforms/emscripten.cmake
+++ b/cmake/platforms/emscripten.cmake
@@ -47,6 +47,8 @@ set(emcc_export_list
_restore_puzzle_size
# Callback when device pixel ratio changes
_rescale_puzzle
+ # Callback for loading user preferences
+ _prefs_load_callback
# Main program, run at initialisation time
_main)
diff --git a/emcc.c b/emcc.c
index 5338dd4..60ef8c8 100644
--- a/emcc.c
+++ b/emcc.c
@@ -101,6 +101,9 @@ extern void js_focus_canvas(void);
extern bool js_savefile_read(void *buf, int len);
+extern void js_save_prefs(const char *);
+extern void js_load_prefs(midend *);
+
/*
* These functions are called from JavaScript, so their prototypes
* need to be kept in sync with emccpre.js.
@@ -122,6 +125,11 @@ void restore_puzzle_size(int w, int h);
void rescale_puzzle(void);
/*
+ * Internal forward references.
+ */
+static void save_prefs(midend *me);
+
+/*
* Call JS to get the date, and use that to initialise our random
* number generator to invent the first game seed.
*/
@@ -743,10 +751,20 @@ static void cfg_end(bool use_results)
* open for the user to adjust them and try again.
*/
js_error_box(err);
+ } else if (cfg_which == CFG_PREFS) {
+ /*
+ * Acceptable settings for user preferences: enact them
+ * without blowing away the current game.
+ */
+ resize();
+ midend_redraw(me);
+ free_cfg(cfg);
+ js_dialog_cleanup();
+ save_prefs(me);
} else {
/*
- * New settings are fine; start a new game and close the
- * dialog.
+ * Acceptable settings for the remaining configuration
+ * types: start a new game and close the dialog.
*/
select_appropriate_preset();
midend_new_game(me);
@@ -849,6 +867,9 @@ void command(int n)
post_move();
js_focus_canvas();
break;
+ case 10: /* user preferences */
+ cfg_start(CFG_PREFS);
+ break;
}
}
@@ -926,6 +947,64 @@ void load_game(void)
}
/* ----------------------------------------------------------------------
+ * Functions to load and save preferences, calling out to JS to access
+ * the appropriate localStorage slot.
+ */
+
+static void save_prefs(midend *me)
+{
+ struct savefile_write_ctx ctx;
+ size_t size;
+
+ /* First pass, to count up the size */
+ ctx.buffer = NULL;
+ ctx.pos = 0;
+ midend_save_prefs(me, savefile_write, &ctx);
+ size = ctx.pos;
+
+ /* Second pass, to actually write out the data. As with
+ * get_save_file, we append a terminating \0. */
+ ctx.buffer = snewn(size+1, char);
+ ctx.pos = 0;
+ midend_save_prefs(me, savefile_write, &ctx);
+ assert(ctx.pos == size);
+ ctx.buffer[ctx.pos] = '\0';
+
+ js_save_prefs(ctx.buffer);
+
+ sfree(ctx.buffer);
+}
+
+struct prefs_read_ctx {
+ const char *buffer;
+ size_t pos, len;
+};
+
+static bool prefs_read(void *vctx, void *buf, int len)
+{
+ struct prefs_read_ctx *ctx = (struct prefs_read_ctx *)vctx;
+
+ if (len < 0)
+ return false;
+ if (ctx->len - ctx->pos < len)
+ return false;
+ memcpy(buf, ctx->buffer + ctx->pos, len);
+ ctx->pos += len;
+ return true;
+}
+
+void prefs_load_callback(midend *me, const char *prefs)
+{
+ struct prefs_read_ctx ctx;
+
+ ctx.buffer = prefs;
+ ctx.len = strlen(prefs);
+ ctx.pos = 0;
+
+ midend_load_prefs(me, prefs_read, &ctx);
+}
+
+/* ----------------------------------------------------------------------
* Setup function called at page load time. It's called main() because
* that's the most convenient thing in Emscripten, but it's not main()
* in the usual sense of bounding the program's entire execution.
@@ -948,6 +1027,7 @@ int main(int argc, char **argv)
* Instantiate a midend.
*/
me = midend_new(NULL, &thegame, &js_drawing, NULL);
+ js_load_prefs(me);
/*
* Chuck in the HTML fragment ID if we have one (trimming the
diff --git a/emcclib.js b/emcclib.js
index 80d17b9..d161c49 100644
--- a/emcclib.js
+++ b/emcclib.js
@@ -792,5 +792,28 @@ mergeInto(LibraryManager.library, {
*/
js_savefile_read: function(buf, len) {
return savefile_read_callback(buf, len);
+ },
+
+ /*
+ * void js_save_prefs(const char *);
+ *
+ * Write a buffer of serialised preferences data into localStorage.
+ */
+ js_save_prefs: function(buf) {
+ var prefsdata = UTF8ToString(buf);
+ localStorage.setItem(location.pathname + "#preferences", prefsdata);
+ },
+
+ /*
+ * void js_load_prefs(midend *);
+ *
+ * Retrieve preferences data from localStorage. If there is any,
+ * pass it back in as a string, via prefs_load_callback.
+ */
+ js_load_prefs: function(me) {
+ var prefsdata = localStorage.getItem(location.pathname+"#preferences");
+ if (prefsdata !== undefined && prefsdata !== null) {
+ prefs_load_callback(me, prefsdata);
+ }
}
});
diff --git a/emccpre.js b/emccpre.js
index 7c68445..a114ce1 100644
--- a/emccpre.js
+++ b/emccpre.js
@@ -141,6 +141,11 @@ var dlg_return_sval, dlg_return_ival;
// process of loading at a time.
var savefile_read_callback;
+// void prefs_load_callback(midend *me, const char *prefs);
+//
+// Callback for passing in preferences data retrieved from localStorage.
+var prefs_load_callback;
+
// The <ul> object implementing the game-type drop-down, and a list of
// the sub-lists inside it. Used by js_add_preset().
var gametypelist = document.getElementById("gametype");
@@ -161,6 +166,7 @@ var permalink_desc = document.getElementById("permalink-desc");
// The various buttons. Undo and redo are used by js_enable_undo_redo().
var specific_button = document.getElementById("specific");
var random_button = document.getElementById("random");
+var prefs_button = document.getElementById("prefs");
var new_button = document.getElementById("new");
var restart_button = document.getElementById("restart");
var undo_button = document.getElementById("undo");
@@ -425,6 +431,10 @@ function initPuzzle() {
if (dlg_dimmer === null)
command(9);
};
+ if (prefs_button) prefs_button.onclick = function(event) {
+ if (dlg_dimmer === null)
+ command(10);
+ };
// 'number' is used for C pointers
var get_save_file = Module.cwrap('get_save_file', 'number', []);
@@ -682,6 +692,8 @@ function initPuzzle() {
dlg_return_ival = Module.cwrap('dlg_return_ival', 'void',
['number','number']);
timer_callback = Module.cwrap('timer_callback', 'void', ['number']);
+ prefs_load_callback = Module.cwrap('prefs_load_callback', 'void',
+ ['number','string']);
if (resizable_div !== null) {
var resize_handle = document.getElementById("resizehandle");
diff --git a/html/jspage.pl b/html/jspage.pl
index de70b30..5c1689e 100755
--- a/html/jspage.pl
+++ b/html/jspage.pl
@@ -340,6 +340,7 @@ ${unfinishedpara}
<li><button type="button" id="random">Enter random seed...</button></li>
<li><button type="button" id="save">Download save file...</button></li>
<li><button type="button" id="load">Upload save file...</button></li>
+ <li><button type="button" id="prefs">Preferences...</button></li>
</ul></div></li>
<li><div tabindex="0">Type<ul role="menu" id="gametype"></ul></div></li>
<li role="separator"></li>
diff --git a/puzzles.but b/puzzles.but
index be55f8e..1e0ebb7 100644
--- a/puzzles.but
+++ b/puzzles.but
@@ -179,10 +179,10 @@ solving it yourself after seeing the answer, you can just press Undo.
\dt \i\e{Preferences}
-\dd Where supported (currently on Windows, Unix and MacOS), brings up
-a dialog allowing you to configure personal preferences about a
-particular game. Some of these preferences will be specific to a
-particular game; others will be common to all games.
+\dd Where supported, brings up a dialog allowing you to configure
+personal preferences about a particular game. Some of these
+preferences will be specific to a particular game; others will be
+common to all games.
\lcont{