diff --git a/emcc.c b/emcc.c index baf12d3..dda5716 100644 --- a/emcc.c +++ b/emcc.c @@ -21,12 +21,6 @@ * by using the DOM File API to ask the user to select a file and * permit us to see its contents. * - * - it ought to be possible to make the puzzle canvases resizable, - * by superimposing some kind of draggable resize handle. Also I - * quite like the idea of having a few buttons for standard sizes: - * reset to default size, maximise to the browser window dimensions - * (if we can find those out), and perhaps even go full-screen. - * * - I should think about whether these webified puzzles can support * touchscreen-based tablet browsers (assuming there are any that * can cope with the reasonably modern JS and run it fast enough to @@ -194,10 +188,12 @@ void timer_callback(double tplus) } /* ---------------------------------------------------------------------- - * Helper function to resize the canvas, and variables to remember its - * size for other functions (e.g. trimming blitter rectangles). + * Helper functions to resize the canvas, and variables to remember + * its size for other functions (e.g. trimming blitter rectangles). */ static int canvas_w, canvas_h; + +/* Called when we resize as a result of changing puzzle settings */ static void resize(void) { int w, h; @@ -208,6 +204,26 @@ static void resize(void) canvas_h = h; } +/* Called from JS when the user uses the resize handle */ +void resize_puzzle(int w, int h) +{ + midend_size(me, &w, &h, TRUE); + if (canvas_w != w || canvas_h != h) { + js_canvas_set_size(w, h); + canvas_w = w; + canvas_h = h; + midend_force_redraw(me); + } +} + +/* Called from JS when the user uses the restore button */ +void restore_puzzle_size(int w, int h) +{ + midend_reset_tilesize(me); + resize(); + midend_force_redraw(me); +} + /* * HTML doesn't give us a default frontend colour of its own, so we * just make up a lightish grey ourselves. diff --git a/emcclib.js b/emcclib.js index e0c4bea..7d001c3 100644 --- a/emcclib.js +++ b/emcclib.js @@ -567,6 +567,7 @@ mergeInto(LibraryManager.library, { 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; diff --git a/emccpre.js b/emccpre.js index 5c1ad4c..5231d04 100644 --- a/emccpre.js +++ b/emccpre.js @@ -103,6 +103,10 @@ var permalink_seed, permalink_desc; // The undo and redo buttons. Used by js_enable_undo_redo(). var undo_button, redo_button; +// A div element enclosing both the puzzle and its status bar, used +// for positioning the resize handle. +var resizable_div; + // Helper function to find the absolute position of a given DOM // element on a page, by iterating upwards through the DOM finding // each element's offset from its parent, and thus calculating the @@ -268,6 +272,83 @@ function initPuzzle() { // Default to giving keyboard focus to the puzzle. onscreen_canvas.focus(); + // Create the resize handle. + var resize_handle = document.createElement("canvas"); + resize_handle.width = 10; + resize_handle.height = 10; + { + var ctx = resize_handle.getContext("2d"); + ctx.beginPath(); + for (var i = 1; i <= 7; i += 3) { + ctx.moveTo(8.5, i + 0.5); + ctx.lineTo(i + 0.5, 8.5); + } + ctx.lineWidth = '1px'; + ctx.lineCap = 'round'; + ctx.lineJoin = 'round'; + ctx.strokeStyle = '#000000'; + ctx.stroke(); + } + resizable_div = document.getElementById("resizable"); + resizable_div.appendChild(resize_handle); + resize_handle.style.position = 'absolute'; + resize_handle.style.zIndex = 98; + resize_handle.style.bottom = "0"; + resize_handle.style.right = "0"; + resize_handle.style.cursor = "se-resize"; + resize_handle.title = "Drag to resize the puzzle. Right-click to restore the default size."; + var resize_xbase = null, resize_ybase = null, restore_pending = false; + var resize_xoffset = null, resize_yoffset = null; + var resize_puzzle = Module.cwrap('resize_puzzle', + 'void', ['number', 'number']); + var restore_puzzle_size = Module.cwrap('restore_puzzle_size', 'void', []); + resize_handle.oncontextmenu = function(event) { return false; } + resize_handle.onmousedown = function(event) { + if (event.button == 0) { + var xy = element_coords(onscreen_canvas); + resize_xbase = xy.x + onscreen_canvas.width / 2; + resize_ybase = xy.y; + resize_xoffset = xy.x + onscreen_canvas.width - event.pageX; + resize_yoffset = xy.y + onscreen_canvas.height - event.pageY; + } else { + restore_pending = true; + } + resize_handle.setCapture(true); + event.preventDefault(); + }; + window.addEventListener("mousemove", function(event) { + if (resize_xbase !== null && resize_ybase !== null) { + resize_puzzle((event.pageX + resize_xoffset - resize_xbase) * 2, + (event.pageY + resize_yoffset - resize_ybase)); + event.preventDefault(); + // Chrome insists on selecting text during a resize drag + // no matter what I do + if (window.getSelection) + window.getSelection().removeAllRanges(); + else + document.selection.empty(); } + }); + window.addEventListener("mouseup", function(event) { + if (resize_xbase !== null && resize_ybase !== null) { + resize_xbase = null; + resize_ybase = null; + onscreen_canvas.focus(); // return focus to the puzzle + } else if (restore_pending) { + // If you have the puzzle at larger than normal size and + // then right-click to restore, I haven't found any way to + // stop Chrome and IE popping up a context menu on the + // revealed piece of document when you release the button + // except by putting the actual restore into a setTimeout. + // Gah. + setTimeout(function() { + restore_pending = false; + restore_puzzle_size(); + onscreen_canvas.focus(); + }, 20); + } + event.preventDefault(); + }); + // Run the C setup function, passing argv[1] as the fragment // identifier (so that permalinks of the form puzzle.html#game-id // can launch the specified id). diff --git a/emccx.json b/emccx.json index 31d7234..e03f7e2 100644 --- a/emccx.json +++ b/emccx.json @@ -21,6 +21,9 @@ // Callbacks to return values from dialog boxes '_dlg_return_sval', '_dlg_return_ival', + // Callbacks when the resizing controls are used + '_resize_puzzle', + '_restore_puzzle_size', // Main program, run at initialisation time '_main' ] diff --git a/html/jspage.pl b/html/jspage.pl index d6e4167..19868bd 100755 --- a/html/jspage.pl +++ b/html/jspage.pl @@ -84,10 +84,12 @@ ${unfinishedpara}
Link to this puzzle: by game ID