X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=emcclib.js;h=907dc19995ea326001b9ca307d346bfe3d421a8c;hb=db313b3948d27244dd7c34c2609c66d6204d8931;hp=51c8f93bb94d95cb45fa21426310ed9ff84010d6;hpb=49fba922eac8c4022b002e340080be9a7134132e;p=sgt-puzzles.git diff --git a/emcclib.js b/emcclib.js index 51c8f93..907dc19 100644 --- a/emcclib.js +++ b/emcclib.js @@ -2,7 +2,11 @@ * emcclib.js: one of the Javascript components of an Emscripten-based * web/Javascript front end for Puzzles. * - * The other parts of this system live in emcc.c and emccpre.js. + * The other parts of this system live in emcc.c and emccpre.js. It + * also depends on being run in the context of a web page containing + * an appropriate collection of bits and pieces (a canvas, some + * buttons and links etc), which is generated for each puzzle by the + * script html/jspage.pl. * * This file contains a set of Javascript functions which we insert * into Emscripten's library object via the --js-library option; this @@ -41,7 +45,7 @@ mergeInto(LibraryManager.library, { * provides neither presets nor configurability. */ js_remove_type_dropdown: function() { - document.getElementById("gametype").style.display = "none"; + gametypelist.style.display = "none"; }, /* @@ -55,19 +59,60 @@ mergeInto(LibraryManager.library, { }, /* - * void js_add_preset(const char *name); + * void js_add_preset(int menuid, const char *name, int value); * - * Add a preset to the drop-down types menu. The provided text is - * the name of the preset. (The corresponding game_params stays on - * the C side and never comes out this far; we just pass a numeric - * index back to the C code when a selection is made.) - */ - js_add_preset: function(ptr) { - var option = document.createElement("option"); - option.value = Pointer_stringify(ptr); - option.innerHTML = Pointer_stringify(ptr); - gametypeselector.appendChild(option); - gametypeoptions.push(option); + * Add a preset to the drop-down types menu, or to a submenu of + * it. 'menuid' specifies an index into our array of submenus + * where the item might be placed; 'value' specifies the number + * that js_get_selected_preset() will return when this item is + * clicked. + */ + js_add_preset: function(menuid, ptr, value) { + var name = Pointer_stringify(ptr); + var item = document.createElement("li"); + item.setAttribute("data-index", value); + var tick = document.createElement("span"); + tick.appendChild(document.createTextNode("\u2713")); + tick.style.color = "transparent"; + tick.style.paddingRight = "0.5em"; + item.appendChild(tick); + item.appendChild(document.createTextNode(name)); + gametypesubmenus[menuid].appendChild(item); + gametypeitems.push(item); + + item.onclick = function(event) { + if (dlg_dimmer === null) { + gametypeselectedindex = value; + command(2); + } + } + }, + + /* + * int js_add_preset_submenu(int menuid, const char *name); + * + * Add a submenu in the presets menu hierarchy. Returns its index, + * for passing as the 'menuid' argument in further calls to + * js_add_preset or this function. + */ + js_add_preset_submenu: function(menuid, ptr, value) { + var name = Pointer_stringify(ptr); + var item = document.createElement("li"); + // We still create a transparent tick element, even though it + // won't ever be selected, to make submenu titles line up + // nicely with their neighbours. + var tick = document.createElement("span"); + tick.appendChild(document.createTextNode("\u2713")); + tick.style.color = "transparent"; + tick.style.paddingRight = "0.5em"; + item.appendChild(tick); + item.appendChild(document.createTextNode(name)); + var submenu = document.createElement("ul"); + item.appendChild(submenu); + gametypesubmenus[menuid].appendChild(item); + var toret = gametypesubmenus.length; + gametypesubmenus.push(submenu); + return toret; }, /* @@ -77,14 +122,7 @@ mergeInto(LibraryManager.library, { * dropdown. */ js_get_selected_preset: function() { - var val = 0; - for (var i in gametypeoptions) { - if (gametypeoptions[i].selected) { - val = i; - break; - } - } - return val; + return gametypeselectedindex; }, /* @@ -95,7 +133,16 @@ mergeInto(LibraryManager.library, { * which turn out to exactly match a preset). */ js_select_preset: function(n) { - gametypeoptions[n].selected = true; + gametypeselectedindex = n; + for (var i in gametypeitems) { + var item = gametypeitems[i]; + var tick = item.firstChild; + if (item.getAttribute("data-index") == n) { + tick.style.color = "inherit"; + } else { + tick.style.color = "transparent"; + } + } }, /* @@ -139,8 +186,8 @@ mergeInto(LibraryManager.library, { * after a move. */ js_enable_undo_redo: function(undo, redo) { - undo_button.disabled = (undo == 0); - redo_button.disabled = (redo == 0); + disable_menu_item(undo_button, (undo == 0)); + disable_menu_item(redo_button, (redo == 0)); }, /* @@ -273,8 +320,8 @@ mergeInto(LibraryManager.library, { ctx.moveTo(x1 + 0.5, y1 + 0.5); ctx.lineTo(x2 + 0.5, y2 + 0.5); ctx.lineWidth = width; - ctx.lineCap = '1'; - ctx.lineJoin = '1'; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; ctx.strokeStyle = colour; ctx.stroke(); ctx.fillStyle = colour; @@ -302,8 +349,8 @@ mergeInto(LibraryManager.library, { ctx.fill(); } ctx.lineWidth = '1'; - ctx.lineCap = '1'; - ctx.lineJoin = '1'; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; ctx.strokeStyle = Pointer_stringify(outline); ctx.stroke(); }, @@ -323,8 +370,8 @@ mergeInto(LibraryManager.library, { ctx.fill(); } ctx.lineWidth = '1'; - ctx.lineCap = '1'; - ctx.lineJoin = '1'; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; ctx.strokeStyle = Pointer_stringify(outline); ctx.stroke(); }, @@ -359,7 +406,7 @@ mergeInto(LibraryManager.library, { // Find the width of the string var ctx1 = onscreen_canvas.getContext('2d'); ctx1.font = font; - var width = ctx1.measureText(midpoint_test_str).width; + var width = (ctx1.measureText(midpoint_test_str).width + 1) | 0; // Construct a test canvas of appropriate size, initialise it to // black, and draw the string on it in white @@ -423,6 +470,7 @@ mergeInto(LibraryManager.library, { blitters[id] = document.createElement("canvas"); blitters[id].width = w; blitters[id].height = h; + return id; }, /* @@ -472,18 +520,20 @@ mergeInto(LibraryManager.library, { * back end turns out to want one. */ js_canvas_make_statusbar: function() { - var statustd = document.getElementById("statusbarholder"); + var statusholder = document.getElementById("statusbarholder"); statusbar = document.createElement("div"); statusbar.style.overflow = "hidden"; - statusbar.style.width = onscreen_canvas.width - 4; + statusbar.style.width = (onscreen_canvas.width - 4) + "px"; + statusholder.style.width = onscreen_canvas.width + "px"; statusbar.style.height = "1.2em"; + statusbar.style.textAlign = "left"; statusbar.style.background = "#d8d8d8"; statusbar.style.borderLeft = '2px solid #c8c8c8'; statusbar.style.borderTop = '2px solid #c8c8c8'; statusbar.style.borderRight = '2px solid #e8e8e8'; statusbar.style.borderBottom = '2px solid #e8e8e8'; statusbar.appendChild(document.createTextNode(" ")); - statustd.appendChild(statusbar); + statusholder.appendChild(statusbar); }, /* @@ -507,8 +557,11 @@ mergeInto(LibraryManager.library, { js_canvas_set_size: function(w, h) { onscreen_canvas.width = w; offscreen_canvas.width = w; - if (statusbar !== null) - statusbar.style.width = w - 4; + if (statusbar !== null) { + statusbar.style.width = (w - 4) + "px"; + document.getElementById("statusbarholder").style.width = w + "px"; + } + resizable_div.style.width = w + "px"; onscreen_canvas.height = h; offscreen_canvas.height = h; @@ -521,38 +574,7 @@ mergeInto(LibraryManager.library, { * overlay on top of the rest of the puzzle web page. */ js_dialog_init: function(titletext) { - // Create an overlay on the page which darkens everything - // beneath it. - dlg_dimmer = document.createElement("div"); - dlg_dimmer.style.width = "100%"; - dlg_dimmer.style.height = "100%"; - dlg_dimmer.style.background = '#000000'; - dlg_dimmer.style.position = 'fixed'; - dlg_dimmer.style.opacity = 0.3; - dlg_dimmer.style.top = dlg_dimmer.style.left = 0; - dlg_dimmer.style["z-index"] = 99; - - // Now create a form which sits on top of that in turn. - dlg_form = document.createElement("form"); - dlg_form.style.width = window.innerWidth * 2 / 3; - dlg_form.style.opacity = 1; - dlg_form.style.background = '#ffffff'; - dlg_form.style.color = '#000000'; - dlg_form.style.position = 'absolute'; - dlg_form.style.border = "2px solid black"; - dlg_form.style.padding = 20; - dlg_form.style.top = window.innerHeight / 10; - dlg_form.style.left = window.innerWidth / 6; - dlg_form.style["z-index"] = 100; - - var title = document.createElement("p"); - title.style.marginTop = "0px"; - title.appendChild(document.createTextNode - (Pointer_stringify(titletext))); - dlg_form.appendChild(title); - - dlg_return_funcs = []; - dlg_next_id = 0; + dialog_init(Pointer_stringify(titletext)); }, /* @@ -592,8 +614,8 @@ mergeInto(LibraryManager.library, { var options = []; for (var i in items) { var option = document.createElement("option"); - option.value = items[i]; - option.innerHTML = items[i]; + option.value = i; + option.appendChild(document.createTextNode(items[i])); if (i == initvalue) option.selected = true; dropdown.appendChild(option); options.push(option); @@ -605,7 +627,7 @@ mergeInto(LibraryManager.library, { var val = 0; for (var i in options) { if (options[i].selected) { - val = i; + val = options[i].value; break; } } @@ -647,29 +669,13 @@ mergeInto(LibraryManager.library, { * everything else on the page. */ js_dialog_launch: function() { - // Put in the OK and Cancel buttons at the bottom. - var button; - - button = document.createElement("input"); - button.type = "button"; - button.value = "OK"; - button.onclick = function(event) { + dialog_launch(function(event) { for (var i in dlg_return_funcs) dlg_return_funcs[i](); - command(3); - } - dlg_form.appendChild(button); - - button = document.createElement("input"); - button.type = "button"; - button.value = "Cancel"; - button.onclick = function(event) { - command(4); - } - dlg_form.appendChild(button); - - document.body.appendChild(dlg_dimmer); - document.body.appendChild(dlg_form); + command(3); // OK + }, function(event) { + command(4); // Cancel + }); }, /* @@ -679,10 +685,7 @@ mergeInto(LibraryManager.library, { * associated with it. */ js_dialog_cleanup: function() { - document.body.removeChild(dlg_dimmer); - document.body.removeChild(dlg_form); - dlg_dimmer = dlg_form = null; - onscreen_canvas.focus(); + dialog_cleanup(); }, /* @@ -694,5 +697,5 @@ mergeInto(LibraryManager.library, { */ js_focus_canvas: function() { onscreen_canvas.focus(); - }, + } });