shithub: puzzles

Download patch

ref: 36f35f5db81d95c3fc038f27ac791a2f4f748c10
parent: 2360b77812e184902e44c7f4ea2f6fc79729e370
author: Simon Tatham <anakin@pobox.com>
date: Fri Apr 5 11:49:29 EDT 2013

Regretfully remove my trickery with a hidden <option> element inside
the game-type <select>, since IE turns out to ignore display:none on
options. Oh well.

Instead I now do a more transparent thing: when custom game params are
in use, there's a "Custom" option selected in the dropdown, and a
separate 'Re-customise' option which brings the config box back up.
When an ordinary preset is selected, the Custom option is missing, and
there's just a 'Customise'.

In the process I've tinkered a bit to arrange that the custom 'preset'
is always represented by a negative number rather than one past the
last real preset; that seems more consistent overall.

[originally from svn r9811]

--- a/emcc.c
+++ b/emcc.c
@@ -53,6 +53,7 @@
  *    that using whatever they normally use to print PDFs!)
  */
 
+#include <assert.h>
 #include <string.h>
 
 #include "puzzles.h"
@@ -528,7 +529,7 @@
  * Presets and game-configuration dialog support.
  */
 static game_params **presets;
-static int custom_preset;
+static int npresets;
 int have_presets_dropdown;
 
 void select_appropriate_preset(void)
@@ -535,7 +536,7 @@
 {
     if (have_presets_dropdown) {
         int preset = midend_which_preset(me);
-        js_select_preset(preset < 0 ? custom_preset : preset);
+        js_select_preset(preset < 0 ? -1 : preset);
     }
 }
 
@@ -656,7 +657,7 @@
       case 2:                          /* game parameter dropdown changed */
         {
             int i = js_get_selected_preset();
-            if (i == custom_preset) {
+            if (i < 0) {
                 /*
                  * The user selected 'Custom', so launch the config
                  * box.
@@ -668,6 +669,7 @@
                  * The user selected a preset, so just switch straight
                  * to that.
                  */
+                assert(i < npresets);
                 midend_set_params(me, presets[i]);
                 midend_new_game(me);
                 resize();
@@ -674,6 +676,7 @@
                 midend_redraw(me);
                 update_undo_redo();
                 js_focus_canvas();
+                select_appropriate_preset(); /* sort out Custom/Customise */
             }
         }
         break;
@@ -762,12 +765,10 @@
 
     /*
      * Set up the game-type dropdown with presets and/or the Custom
-     * option. We remember the index of the Custom option (as
-     * custom_preset) so that we can easily treat it specially when
-     * it's selected.
+     * option.
      */
-    custom_preset = midend_num_presets(me);
-    if (custom_preset == 0) {
+    npresets = midend_num_presets(me);
+    if (npresets == 0) {
         /*
          * This puzzle doesn't have selectable game types at all.
          * Completely remove the drop-down list from the page.
@@ -777,8 +778,8 @@
     } else {
         int preset;
 
-        presets = snewn(custom_preset, game_params *);
-        for (i = 0; i < custom_preset; i++) {
+        presets = snewn(npresets, game_params *);
+        for (i = 0; i < npresets; i++) {
             char *name;
             midend_fetch_preset(me, i, &name, &presets[i]);
             js_add_preset(name);
--- a/emcclib.js
+++ b/emcclib.js
@@ -71,7 +71,7 @@
      * case we need to do something special - see below.
      */
     js_add_preset: function(ptr) {
-        var name = (ptr == 0 ? "Custom..." : Pointer_stringify(ptr));
+        var name = (ptr == 0 ? "Customise..." : Pointer_stringify(ptr));
         var value = gametypeoptions.length;
 
         var option = document.createElement("option");
@@ -81,39 +81,20 @@
         gametypeoptions.push(option);
 
         if (ptr == 0) {
-            // Create a _second_ element called 'Custom', which is
-            // hidden.
-            //
-            // Hiding this element (that is, setting it display:none)
-            // has the effect of making it not show up when the
-            // drop-down list is actually opened, but still show up
-            // when the item is selected.
-            //
-            // So what happens is that there's one element marked
-            // 'Custom' that the _user_ selects, but a second one to
-            // which we reset the dropdown after the config box
-            // returns (if we don't then turn out to select a
-            // different preset anyway). The point is that if the user
-            // has 'Custom' selected, but then wants to customise
-            // their settings a second time, we still get an onchange
-            // event when they select the Custom option again, which
-            // we wouldn't get if the browser thought it was already
-            // the selected one. But here, it's _not_ the selected
-            // option already; its invisible evil twin is selected.
-            //
-            // (Actually, they're not _identical_ evil twins: we label
-            // the two slightly differently. The visible one that the
-            // user can select is labelled "Custom..." to hint that it
-            // opens a dialog box, whereas the invisible one that's
-            // left shown after the box closes is just "Custom",
-            // because that's telling you what you _have_ got
-            // selected.)
+            // The option we've just created is the one for inventing
+            // a new custom setup.
+            gametypenewcustom = option;
+            option.value = -1;
+
+            // Now create another element called 'Custom', which will
+            // be auto-selected by us to indicate the custom settings
+            // you've previously selected. However, we don't add it to
+            // the game type selector; it will only appear when the
+            // user actually has custom settings selected.
             option = document.createElement("option");
-            option.value = value;
+            option.value = -2;
             option.appendChild(document.createTextNode("Custom"));
-            option.style.display = "none";
-            gametypeselector.appendChild(option);
-            gametypehiddencustom = option;
+            gametypethiscustom = option;
         }
     },
 
@@ -140,11 +121,31 @@
      * which turn out to exactly match a preset).
      */
     js_select_preset: function(n) {
-        if (gametypeoptions[n].value == gametypehiddencustom.value) {
-            // If we're asked to select the visible Custom option,
-            // select the invisible one instead. See comment above in
-            // js_add_preset.
-            gametypehiddencustom.selected = true;
+        if (gametypethiscustom !== null) {
+            // Fiddle with the Custom/Customise options. If we're
+            // about to select the Custom option, then it should be in
+            // the menu, and the other one should read "Re-customise";
+            // if we're about to select another one, then the static
+            // Custom option should disappear and the other one should
+            // read "Customise".
+
+            if (gametypethiscustom.parentNode == gametypeselector)
+                gametypeselector.removeChild(gametypethiscustom);
+            if (gametypenewcustom.parentNode == gametypeselector)
+                gametypeselector.removeChild(gametypenewcustom);
+
+            if (n < 0) {
+                gametypeselector.appendChild(gametypethiscustom);
+                gametypenewcustom.lastChild.data = "Re-customise...";
+            } else {
+                gametypenewcustom.lastChild.data = "Customise...";
+            }
+            gametypeselector.appendChild(gametypenewcustom);
+            gametypenewcustom.selected = false;
+        }
+
+        if (n < 0) {
+            gametypethiscustom.selected = true;
         } else {
             gametypeoptions[n].selected = true;
         }
--- a/emccpre.js
+++ b/emccpre.js
@@ -83,13 +83,18 @@
 // list of the <option> objects inside it. Used by js_add_preset(),
 // js_get_selected_preset() and js_select_preset().
 //
-// gametypehiddencustom is a second copy of the 'Custom' dropdown
-// element, set to display:none. This is used by a bodge in emcclib.js
-// (see comment in js_add_preset) to arrange that if the Custom
-// element is (apparently) already selected, we still find out if the
-// user selects it again.
+// gametypethiscustom is an option which indicates some custom game
+// params you've already set up, and which will be auto-selected on
+// return from the customisation dialog; gametypenewcustom is an
+// option which you select to indicate that you want to bring up the
+// customisation dialog and select a new configuration. Ideally I'd do
+// this with just one option serving both purposes, but instead we
+// have to do this a bit oddly because browsers don't send 'onchange'
+// events for a select element if you reselect the same one - so if
+// you've picked a custom setup and now want to change it, you need a
+// way to specify that.
 var gametypeselector = null, gametypeoptions = [];
-var gametypehiddencustom = null;
+var gametypethiscustom = null, gametypehiddencustom = null;
 
 // The two anchors used to give permalinks to the current puzzle. Used
 // by js_update_permalinks().