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]
This commit is contained in:
Simon Tatham
2013-04-05 15:49:29 +00:00
parent 2360b77812
commit 36f35f5db8
3 changed files with 60 additions and 53 deletions

21
emcc.c
View File

@ -53,6 +53,7 @@
* that using whatever they normally use to print PDFs!) * that using whatever they normally use to print PDFs!)
*/ */
#include <assert.h>
#include <string.h> #include <string.h>
#include "puzzles.h" #include "puzzles.h"
@ -528,14 +529,14 @@ const struct drawing_api js_drawing = {
* Presets and game-configuration dialog support. * Presets and game-configuration dialog support.
*/ */
static game_params **presets; static game_params **presets;
static int custom_preset; static int npresets;
int have_presets_dropdown; int have_presets_dropdown;
void select_appropriate_preset(void) void select_appropriate_preset(void)
{ {
if (have_presets_dropdown) { if (have_presets_dropdown) {
int preset = midend_which_preset(me); 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 @@ void command(int n)
case 2: /* game parameter dropdown changed */ case 2: /* game parameter dropdown changed */
{ {
int i = js_get_selected_preset(); int i = js_get_selected_preset();
if (i == custom_preset) { if (i < 0) {
/* /*
* The user selected 'Custom', so launch the config * The user selected 'Custom', so launch the config
* box. * box.
@ -668,12 +669,14 @@ void command(int n)
* The user selected a preset, so just switch straight * The user selected a preset, so just switch straight
* to that. * to that.
*/ */
assert(i < npresets);
midend_set_params(me, presets[i]); midend_set_params(me, presets[i]);
midend_new_game(me); midend_new_game(me);
resize(); resize();
midend_redraw(me); midend_redraw(me);
update_undo_redo(); update_undo_redo();
js_focus_canvas(); js_focus_canvas();
select_appropriate_preset(); /* sort out Custom/Customise */
} }
} }
break; break;
@ -762,12 +765,10 @@ int main(int argc, char **argv)
/* /*
* Set up the game-type dropdown with presets and/or the Custom * Set up the game-type dropdown with presets and/or the Custom
* option. We remember the index of the Custom option (as * option.
* custom_preset) so that we can easily treat it specially when
* it's selected.
*/ */
custom_preset = midend_num_presets(me); npresets = midend_num_presets(me);
if (custom_preset == 0) { if (npresets == 0) {
/* /*
* This puzzle doesn't have selectable game types at all. * This puzzle doesn't have selectable game types at all.
* Completely remove the drop-down list from the page. * Completely remove the drop-down list from the page.
@ -777,8 +778,8 @@ int main(int argc, char **argv)
} else { } else {
int preset; int preset;
presets = snewn(custom_preset, game_params *); presets = snewn(npresets, game_params *);
for (i = 0; i < custom_preset; i++) { for (i = 0; i < npresets; i++) {
char *name; char *name;
midend_fetch_preset(me, i, &name, &presets[i]); midend_fetch_preset(me, i, &name, &presets[i]);
js_add_preset(name); js_add_preset(name);

View File

@ -71,7 +71,7 @@ mergeInto(LibraryManager.library, {
* case we need to do something special - see below. * case we need to do something special - see below.
*/ */
js_add_preset: function(ptr) { 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 value = gametypeoptions.length;
var option = document.createElement("option"); var option = document.createElement("option");
@ -81,39 +81,20 @@ mergeInto(LibraryManager.library, {
gametypeoptions.push(option); gametypeoptions.push(option);
if (ptr == 0) { if (ptr == 0) {
// Create a _second_ element called 'Custom', which is // The option we've just created is the one for inventing
// hidden. // a new custom setup.
// gametypenewcustom = option;
// Hiding this element (that is, setting it display:none) option.value = -1;
// has the effect of making it not show up when the
// drop-down list is actually opened, but still show up // Now create another element called 'Custom', which will
// when the item is selected. // be auto-selected by us to indicate the custom settings
// // you've previously selected. However, we don't add it to
// So what happens is that there's one element marked // the game type selector; it will only appear when the
// 'Custom' that the _user_ selects, but a second one to // user actually has custom settings selected.
// 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.)
option = document.createElement("option"); option = document.createElement("option");
option.value = value; option.value = -2;
option.appendChild(document.createTextNode("Custom")); option.appendChild(document.createTextNode("Custom"));
option.style.display = "none"; gametypethiscustom = option;
gametypeselector.appendChild(option);
gametypehiddencustom = option;
} }
}, },
@ -140,11 +121,31 @@ mergeInto(LibraryManager.library, {
* which turn out to exactly match a preset). * which turn out to exactly match a preset).
*/ */
js_select_preset: function(n) { js_select_preset: function(n) {
if (gametypeoptions[n].value == gametypehiddencustom.value) { if (gametypethiscustom !== null) {
// If we're asked to select the visible Custom option, // Fiddle with the Custom/Customise options. If we're
// select the invisible one instead. See comment above in // about to select the Custom option, then it should be in
// js_add_preset. // the menu, and the other one should read "Re-customise";
gametypehiddencustom.selected = true; // 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 { } else {
gametypeoptions[n].selected = true; gametypeoptions[n].selected = true;
} }

View File

@ -83,13 +83,18 @@ var dlg_return_sval, dlg_return_ival;
// list of the <option> objects inside it. Used by js_add_preset(), // list of the <option> objects inside it. Used by js_add_preset(),
// js_get_selected_preset() and js_select_preset(). // js_get_selected_preset() and js_select_preset().
// //
// gametypehiddencustom is a second copy of the 'Custom' dropdown // gametypethiscustom is an option which indicates some custom game
// element, set to display:none. This is used by a bodge in emcclib.js // params you've already set up, and which will be auto-selected on
// (see comment in js_add_preset) to arrange that if the Custom // return from the customisation dialog; gametypenewcustom is an
// element is (apparently) already selected, we still find out if the // option which you select to indicate that you want to bring up the
// user selects it again. // 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 gametypeselector = null, gametypeoptions = [];
var gametypehiddencustom = null; var gametypethiscustom = null, gametypehiddencustom = null;
// The two anchors used to give permalinks to the current puzzle. Used // The two anchors used to give permalinks to the current puzzle. Used
// by js_update_permalinks(). // by js_update_permalinks().