mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-17 09:02:38 -05:00
puzzles: resync with upstream
This brings puzzles to upstream commit 84d3fd2. Change-Id: I808a197f868032d771fc101a15666c5ec4b9f94b
This commit is contained in:
parent
ea679de837
commit
b9386109e8
26 changed files with 1037 additions and 583 deletions
|
|
@ -54,24 +54,30 @@ in puzzles do make -f Makefile.doc clean
|
||||||
in puzzles do make -f Makefile.doc # build help files for installer
|
in puzzles do make -f Makefile.doc # build help files for installer
|
||||||
in puzzles do mason.pl --args '{"version":"$(Version)","descfile":"gamedesc.txt"}' winwix.mc > puzzles.wxs
|
in puzzles do mason.pl --args '{"version":"$(Version)","descfile":"gamedesc.txt"}' winwix.mc > puzzles.wxs
|
||||||
in puzzles do perl winiss.pl $(Version) gamedesc.txt > puzzles.iss
|
in puzzles do perl winiss.pl $(Version) gamedesc.txt > puzzles.iss
|
||||||
delegate windows
|
ifneq "$(VISUAL_STUDIO)" "yes" then
|
||||||
# FIXME: Cygwin alternative?
|
in puzzles with clangcl64 do Platform=x64 make -f Makefile.clangcl clean
|
||||||
in puzzles with visualstudio do/win nmake -f Makefile.vc clean
|
in puzzles with clangcl64 do Platform=x64 make -f Makefile.clangcl VER=-DVER=$(Version)
|
||||||
in puzzles with visualstudio do/win nmake -f Makefile.vc VER=-DVER=$(Version)
|
|
||||||
# Code-sign the binaries, if the local bob config provides a script
|
# Code-sign the binaries, if the local bob config provides a script
|
||||||
# to do so. We assume here that the script accepts an -i option to
|
# to do so. We assume here that the script accepts an -i option to
|
||||||
# provide a 'more info' URL, and an optional -n option to provide a
|
# provide a 'more info' URL, and an optional -n option to provide a
|
||||||
# program name, and that it can take multiple .exe filename
|
# program name, and that it can take multiple .exe filename
|
||||||
# arguments and sign them all in place.
|
# arguments and sign them all in place.
|
||||||
ifneq "$(winsigncode)" "" in puzzles do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/puzzles/ *.exe
|
ifneq "$(cross_winsigncode)" "" in puzzles do $(cross_winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/puzzles/ *.exe
|
||||||
# Build installers.
|
# Build installers.
|
||||||
in puzzles with wix do/win candle puzzles.wxs && light -ext WixUIExtension -sval puzzles.wixobj
|
in puzzles with wixonlinux do candle -arch x64 puzzles.wxs && light -ext WixUIExtension -sval puzzles.wixobj
|
||||||
in puzzles with innosetup do/win iscc puzzles.iss
|
ifneq "$(cross_winsigncode)" "" in puzzles do $(cross_winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/puzzles/ -n "Simon Tatham's Portable Puzzle Collection Installer" puzzles.msi
|
||||||
ifneq "$(winsigncode)" "" in puzzles do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/puzzles/ -n "Simon Tatham's Portable Puzzle Collection Installer" puzzles.msi Output/installer.exe
|
else
|
||||||
return puzzles/*.exe
|
delegate windows
|
||||||
return puzzles/Output/installer.exe
|
in puzzles with visualstudio do/win nmake -f Makefile.vc clean
|
||||||
return puzzles/puzzles.msi
|
in puzzles with visualstudio do/win nmake -f Makefile.vc VER=-DVER=$(Version)
|
||||||
enddelegate
|
ifneq "$(winsigncode)" "" in puzzles do $(winsigncode) -i https://www.chiark.greenend.org.uk/~sgtatham/puzzles/ *.exe
|
||||||
|
# Build installers.
|
||||||
|
in puzzles with wix do/win candle puzzles.wxs && light -ext WixUIExtension -sval puzzles.wixobj
|
||||||
|
in puzzles with innosetup do/win iscc puzzles.iss
|
||||||
|
return puzzles/*.exe
|
||||||
|
return puzzles/puzzles.msi
|
||||||
|
enddelegate
|
||||||
|
endif
|
||||||
in puzzles do chmod +x *.exe
|
in puzzles do chmod +x *.exe
|
||||||
|
|
||||||
# Build the Pocket PC binaries and CAB.
|
# Build the Pocket PC binaries and CAB.
|
||||||
|
|
@ -152,13 +158,22 @@ delegate emscripten
|
||||||
return puzzles/js/*.js
|
return puzzles/js/*.js
|
||||||
enddelegate
|
enddelegate
|
||||||
|
|
||||||
|
# Build a set of wrapping HTML pages for easy testing of the
|
||||||
|
# Javascript puzzles. These aren't quite the same as the versions that
|
||||||
|
# will go on my live website, because those ones will substitute in a
|
||||||
|
# different footer, and not have to link to the .js files with the
|
||||||
|
# ../js/ prefix. But these ones should be good enough to just open
|
||||||
|
# using a file:// URL in a browser after running a build, and make
|
||||||
|
# sure the main functionality works.
|
||||||
|
in puzzles do mkdir jstest
|
||||||
|
in puzzles/jstest do ../html/jspage.pl --jspath=../js/ /dev/null ../html/*.html
|
||||||
|
|
||||||
# Set up .htaccess containing a redirect for the archive filename.
|
# Set up .htaccess containing a redirect for the archive filename.
|
||||||
in puzzles do echo "AddType application/octet-stream .chm" > .htaccess
|
in puzzles do echo "AddType application/octet-stream .chm" > .htaccess
|
||||||
in puzzles do echo "AddType application/octet-stream .hlp" >> .htaccess
|
in puzzles do echo "AddType application/octet-stream .hlp" >> .htaccess
|
||||||
in puzzles do echo "AddType application/octet-stream .cnt" >> .htaccess
|
in puzzles do echo "AddType application/octet-stream .cnt" >> .htaccess
|
||||||
in . do set -- puzzles*.tar.gz; echo RedirectMatch temp '(.*/)'puzzles.tar.gz '$$1'"$$1" >> puzzles/.htaccess
|
in . do set -- puzzles*.tar.gz; echo RedirectMatch temp '(.*/)'puzzles.tar.gz '$$1'"$$1" >> puzzles/.htaccess
|
||||||
in puzzles do echo RedirectMatch temp '(.*/)'puzzles-installer.msi '$$1'puzzles-$(Version)-installer.msi >> .htaccess
|
in puzzles do echo RedirectMatch temp '(.*/)'puzzles-installer.msi '$$1'puzzles-$(Version)-installer.msi >> .htaccess
|
||||||
in puzzles do echo RedirectMatch temp '(.*/)'puzzles-installer.exe '$$1'puzzles-$(Version)-installer.exe >> .htaccess
|
|
||||||
|
|
||||||
# Phew, we're done. Deliver everything!
|
# Phew, we're done. Deliver everything!
|
||||||
deliver puzzles/icons/*-web.png $@
|
deliver puzzles/icons/*-web.png $@
|
||||||
|
|
@ -172,9 +187,9 @@ deliver puzzles/puzzles.hlp $@
|
||||||
deliver puzzles/puzzles.cnt $@
|
deliver puzzles/puzzles.cnt $@
|
||||||
deliver puzzles/puzzles.zip $@
|
deliver puzzles/puzzles.zip $@
|
||||||
deliver puzzles/puzzles.msi puzzles-$(Version)-installer.msi
|
deliver puzzles/puzzles.msi puzzles-$(Version)-installer.msi
|
||||||
deliver puzzles/Output/installer.exe puzzles-$(Version)-installer.exe
|
|
||||||
deliver puzzles/*.jar java/$@
|
deliver puzzles/*.jar java/$@
|
||||||
deliver puzzles/js/*.js js/$@
|
deliver puzzles/js/*.js js/$@
|
||||||
|
deliver puzzles/jstest/*.html jstest/$@
|
||||||
deliver puzzles/html/*.html html/$@
|
deliver puzzles/html/*.html html/$@
|
||||||
deliver puzzles/html/*.pl html/$@
|
deliver puzzles/html/*.pl html/$@
|
||||||
deliver puzzles/wwwspans.html $@
|
deliver puzzles/wwwspans.html $@
|
||||||
|
|
|
||||||
|
|
@ -61,19 +61,19 @@ public class PuzzleApplet extends JApplet implements Runtime.CallJavaCB {
|
||||||
JMenuBar menubar = new JMenuBar();
|
JMenuBar menubar = new JMenuBar();
|
||||||
JMenu jm;
|
JMenu jm;
|
||||||
menubar.add(jm = new JMenu("Game"));
|
menubar.add(jm = new JMenu("Game"));
|
||||||
addMenuItemWithKey(jm, "New", 'n');
|
addMenuItemCallback(jm, "New", "jcallback_newgame_event");
|
||||||
addMenuItemCallback(jm, "Restart", "jcallback_restart_event");
|
addMenuItemCallback(jm, "Restart", "jcallback_restart_event");
|
||||||
addMenuItemCallback(jm, "Specific...", "jcallback_config_event", CFG_DESC);
|
addMenuItemCallback(jm, "Specific...", "jcallback_config_event", CFG_DESC);
|
||||||
addMenuItemCallback(jm, "Random Seed...", "jcallback_config_event", CFG_SEED);
|
addMenuItemCallback(jm, "Random Seed...", "jcallback_config_event", CFG_SEED);
|
||||||
jm.addSeparator();
|
jm.addSeparator();
|
||||||
addMenuItemWithKey(jm, "Undo", 'u');
|
addMenuItemCallback(jm, "Undo", "jcallback_undo_event");
|
||||||
addMenuItemWithKey(jm, "Redo", 'r');
|
addMenuItemCallback(jm, "Redo", "jcallback_redo_event");
|
||||||
jm.addSeparator();
|
jm.addSeparator();
|
||||||
solveCommand = addMenuItemCallback(jm, "Solve", "jcallback_solve_event");
|
solveCommand = addMenuItemCallback(jm, "Solve", "jcallback_solve_event");
|
||||||
solveCommand.setEnabled(false);
|
solveCommand.setEnabled(false);
|
||||||
if (mainWindow != null) {
|
if (mainWindow != null) {
|
||||||
jm.addSeparator();
|
jm.addSeparator();
|
||||||
addMenuItemWithKey(jm, "Exit", 'q');
|
addMenuItemCallback(jm, "Exit", "jcallback_quit_event");
|
||||||
}
|
}
|
||||||
menubar.add(typeMenu = new JMenu("Type"));
|
menubar.add(typeMenu = new JMenu("Type"));
|
||||||
typeMenu.setVisible(false);
|
typeMenu.setVisible(false);
|
||||||
|
|
@ -126,7 +126,12 @@ public class PuzzleApplet extends JApplet implements Runtime.CallJavaCB {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void keyTyped(KeyEvent e) {
|
public void keyTyped(KeyEvent e) {
|
||||||
runtimeCall("jcallback_key_event", new int[] {0, 0, e.getKeyChar()});
|
int key = e.getKeyChar();
|
||||||
|
if (key == 26 && e.isShiftDown() && e.isControlDown()) {
|
||||||
|
runtimeCall("jcallback_redo_event", new int[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
runtimeCall("jcallback_key_event", new int[] {0, 0, key});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
pp.addMouseListener(new MouseAdapter() {
|
pp.addMouseListener(new MouseAdapter() {
|
||||||
|
|
@ -217,10 +222,6 @@ public class PuzzleApplet extends JApplet implements Runtime.CallJavaCB {
|
||||||
runtimeCall("jcallback_resize", new int[] {pp.getWidth(), pp.getHeight()});
|
runtimeCall("jcallback_resize", new int[] {pp.getWidth(), pp.getHeight()});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMenuItemWithKey(JMenu jm, String name, int key) {
|
|
||||||
addMenuItemCallback(jm, name, "jcallback_menu_key_event", key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private JMenuItem addMenuItemCallback(JMenu jm, String name, final String callback, final int arg) {
|
private JMenuItem addMenuItemCallback(JMenu jm, String name, final String callback, final int arg) {
|
||||||
return addMenuItemCallback(jm, name, callback, new int[] {arg}, false);
|
return addMenuItemCallback(jm, name, callback, new int[] {arg}, false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
!makefile gnustep Makefile.gnustep
|
!makefile gnustep Makefile.gnustep
|
||||||
!makefile nestedvm Makefile.nestedvm
|
!makefile nestedvm Makefile.nestedvm
|
||||||
!makefile emcc Makefile.emcc
|
!makefile emcc Makefile.emcc
|
||||||
|
!makefile clangcl Makefile.clangcl
|
||||||
|
|
||||||
!srcdir icons/
|
!srcdir icons/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
\# File containing the magic HTML configuration directives to create
|
|
||||||
\# an MS HTML Help project. We put this on the end of the Puzzles
|
|
||||||
\# docs build command line to build the HHP and friends.
|
|
||||||
|
|
||||||
\cfg{html-leaf-level}{infinite}
|
|
||||||
\cfg{html-leaf-contains-contents}{false}
|
|
||||||
\cfg{html-suppress-navlinks}{true}
|
|
||||||
\cfg{html-suppress-address}{true}
|
|
||||||
|
|
||||||
\cfg{html-contents-filename}{index.html}
|
|
||||||
\cfg{html-template-filename}{%k.html}
|
|
||||||
\cfg{html-template-fragment}{%k}
|
|
||||||
|
|
||||||
\cfg{html-mshtmlhelp-chm}{puzzles.chm}
|
|
||||||
\cfg{html-mshtmlhelp-project}{puzzles.hhp}
|
|
||||||
\cfg{html-mshtmlhelp-contents}{puzzles.hhc}
|
|
||||||
\cfg{html-mshtmlhelp-index}{puzzles.hhk}
|
|
||||||
|
|
||||||
\cfg{html-body-end}{}
|
|
||||||
|
|
||||||
\cfg{html-head-end}{<link rel="stylesheet" type="text/css" href="chm.css">}
|
|
||||||
|
|
@ -1928,6 +1928,9 @@ Indeed, even horizontal or vertical lines may be anti-aliased.
|
||||||
|
|
||||||
This function may be used for both drawing and printing.
|
This function may be used for both drawing and printing.
|
||||||
|
|
||||||
|
If the specified thickness is less than 1.0, 1.0 is used.
|
||||||
|
This ensures that thin lines are visible even at small scales.
|
||||||
|
|
||||||
\S{drawing-draw-text} \cw{draw_text()}
|
\S{drawing-draw-text} \cw{draw_text()}
|
||||||
|
|
||||||
\c void draw_text(drawing *dr, int x, int y, int fonttype,
|
\c void draw_text(drawing *dr, int x, int y, int fonttype,
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,8 @@ void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour)
|
||||||
void draw_thick_line(drawing *dr, float thickness,
|
void draw_thick_line(drawing *dr, float thickness,
|
||||||
float x1, float y1, float x2, float y2, int colour)
|
float x1, float y1, float x2, float y2, int colour)
|
||||||
{
|
{
|
||||||
|
if (thickness < 1.0)
|
||||||
|
thickness = 1.0;
|
||||||
if (dr->api->draw_thick_line) {
|
if (dr->api->draw_thick_line) {
|
||||||
dr->api->draw_thick_line(dr->handle, thickness,
|
dr->api->draw_thick_line(dr->handle, thickness,
|
||||||
x1, y1, x2, y2, colour);
|
x1, y1, x2, y2, colour);
|
||||||
|
|
|
||||||
|
|
@ -310,6 +310,8 @@ void key(int keycode, int charcode, const char *key, const char *chr,
|
||||||
keyevent = MOD_NUM_KEYPAD | '7';
|
keyevent = MOD_NUM_KEYPAD | '7';
|
||||||
} else if (!strnullcmp(key, "PageUp") || keycode==33) {
|
} else if (!strnullcmp(key, "PageUp") || keycode==33) {
|
||||||
keyevent = MOD_NUM_KEYPAD | '9';
|
keyevent = MOD_NUM_KEYPAD | '9';
|
||||||
|
} else if (shift && ctrl && (keycode & 0x1F) == 26) {
|
||||||
|
keyevent = UI_REDO;
|
||||||
} else if (chr && chr[0] && !chr[1]) {
|
} else if (chr && chr[0] && !chr[1]) {
|
||||||
keyevent = chr[0] & 0xFF;
|
keyevent = chr[0] & 0xFF;
|
||||||
} else if (keycode >= 96 && keycode < 106) {
|
} else if (keycode >= 96 && keycode < 106) {
|
||||||
|
|
@ -323,10 +325,10 @@ void key(int keycode, int charcode, const char *key, const char *chr,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyevent >= 0) {
|
if (keyevent >= 0) {
|
||||||
if (shift && keyevent >= 0x100)
|
if (shift && (keyevent >= 0x100 && !IS_UI_FAKE_KEY(keyevent)))
|
||||||
keyevent |= MOD_SHFT;
|
keyevent |= MOD_SHFT;
|
||||||
|
|
||||||
if (ctrl) {
|
if (ctrl && !IS_UI_FAKE_KEY(keyevent)) {
|
||||||
if (keyevent >= 0x100)
|
if (keyevent >= 0x100)
|
||||||
keyevent |= MOD_CTRL;
|
keyevent |= MOD_CTRL;
|
||||||
else
|
else
|
||||||
|
|
@ -725,7 +727,7 @@ void command(int n)
|
||||||
update_undo_redo();
|
update_undo_redo();
|
||||||
break;
|
break;
|
||||||
case 5: /* New Game */
|
case 5: /* New Game */
|
||||||
midend_process_key(me, 0, 0, 'n');
|
midend_process_key(me, 0, 0, UI_NEWGAME);
|
||||||
update_undo_redo();
|
update_undo_redo();
|
||||||
js_focus_canvas();
|
js_focus_canvas();
|
||||||
break;
|
break;
|
||||||
|
|
@ -735,12 +737,12 @@ void command(int n)
|
||||||
js_focus_canvas();
|
js_focus_canvas();
|
||||||
break;
|
break;
|
||||||
case 7: /* Undo */
|
case 7: /* Undo */
|
||||||
midend_process_key(me, 0, 0, 'u');
|
midend_process_key(me, 0, 0, UI_UNDO);
|
||||||
update_undo_redo();
|
update_undo_redo();
|
||||||
js_focus_canvas();
|
js_focus_canvas();
|
||||||
break;
|
break;
|
||||||
case 8: /* Redo */
|
case 8: /* Redo */
|
||||||
midend_process_key(me, 0, 0, 'r');
|
midend_process_key(me, 0, 0, UI_REDO);
|
||||||
update_undo_redo();
|
update_undo_redo();
|
||||||
js_focus_canvas();
|
js_focus_canvas();
|
||||||
break;
|
break;
|
||||||
|
|
@ -756,6 +758,83 @@ void command(int n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
* Called from JS to prepare a save-game file, and free one after it's
|
||||||
|
* been used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct savefile_write_ctx {
|
||||||
|
char *buffer;
|
||||||
|
size_t pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void savefile_write(void *vctx, void *buf, int len)
|
||||||
|
{
|
||||||
|
struct savefile_write_ctx *ctx = (struct savefile_write_ctx *)vctx;
|
||||||
|
if (ctx->buffer)
|
||||||
|
memcpy(ctx->buffer + ctx->pos, buf, len);
|
||||||
|
ctx->pos += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *get_save_file(void)
|
||||||
|
{
|
||||||
|
struct savefile_write_ctx ctx;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* First pass, to count up the size */
|
||||||
|
ctx.buffer = NULL;
|
||||||
|
ctx.pos = 0;
|
||||||
|
midend_serialise(me, savefile_write, &ctx);
|
||||||
|
size = ctx.pos;
|
||||||
|
|
||||||
|
/* Second pass, to actually write out the data */
|
||||||
|
ctx.buffer = snewn(size, char);
|
||||||
|
ctx.pos = 0;
|
||||||
|
midend_serialise(me, savefile_write, &ctx);
|
||||||
|
assert(ctx.pos == size);
|
||||||
|
|
||||||
|
return ctx.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_save_file(char *buffer)
|
||||||
|
{
|
||||||
|
sfree(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct savefile_read_ctx {
|
||||||
|
const char *buffer;
|
||||||
|
int len_remaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int savefile_read(void *vctx, void *buf, int len)
|
||||||
|
{
|
||||||
|
struct savefile_read_ctx *ctx = (struct savefile_read_ctx *)vctx;
|
||||||
|
if (ctx->len_remaining < len)
|
||||||
|
return FALSE;
|
||||||
|
memcpy(buf, ctx->buffer, len);
|
||||||
|
ctx->len_remaining -= len;
|
||||||
|
ctx->buffer += len;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_game(const char *buffer, int len)
|
||||||
|
{
|
||||||
|
struct savefile_read_ctx ctx;
|
||||||
|
const char *err;
|
||||||
|
|
||||||
|
ctx.buffer = buffer;
|
||||||
|
ctx.len_remaining = len;
|
||||||
|
err = midend_deserialise(me, savefile_read, &ctx);
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
js_error_box(err);
|
||||||
|
} else {
|
||||||
|
select_appropriate_preset();
|
||||||
|
resize();
|
||||||
|
midend_redraw(me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Setup function called at page load time. It's called main() because
|
* 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()
|
* that's the most convenient thing in Emscripten, but it's not main()
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,6 @@ mergeInto(LibraryManager.library, {
|
||||||
item.appendChild(tick);
|
item.appendChild(tick);
|
||||||
item.appendChild(document.createTextNode(name));
|
item.appendChild(document.createTextNode(name));
|
||||||
var submenu = document.createElement("ul");
|
var submenu = document.createElement("ul");
|
||||||
submenu.className = "left";
|
|
||||||
item.appendChild(submenu);
|
item.appendChild(submenu);
|
||||||
gametypesubmenus[menuid].appendChild(item);
|
gametypesubmenus[menuid].appendChild(item);
|
||||||
var toret = gametypesubmenus.length;
|
var toret = gametypesubmenus.length;
|
||||||
|
|
@ -575,38 +574,7 @@ mergeInto(LibraryManager.library, {
|
||||||
* overlay on top of the rest of the puzzle web page.
|
* overlay on top of the rest of the puzzle web page.
|
||||||
*/
|
*/
|
||||||
js_dialog_init: function(titletext) {
|
js_dialog_init: function(titletext) {
|
||||||
// Create an overlay on the page which darkens everything
|
dialog_init(Pointer_stringify(titletext));
|
||||||
// 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) + "px";
|
|
||||||
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 = "20px";
|
|
||||||
dlg_form.style.top = (window.innerHeight / 10) + "px";
|
|
||||||
dlg_form.style.left = (window.innerWidth / 6) + "px";
|
|
||||||
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;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -701,29 +669,13 @@ mergeInto(LibraryManager.library, {
|
||||||
* everything else on the page.
|
* everything else on the page.
|
||||||
*/
|
*/
|
||||||
js_dialog_launch: function() {
|
js_dialog_launch: function() {
|
||||||
// Put in the OK and Cancel buttons at the bottom.
|
dialog_launch(function(event) {
|
||||||
var button;
|
|
||||||
|
|
||||||
button = document.createElement("input");
|
|
||||||
button.type = "button";
|
|
||||||
button.value = "OK";
|
|
||||||
button.onclick = function(event) {
|
|
||||||
for (var i in dlg_return_funcs)
|
for (var i in dlg_return_funcs)
|
||||||
dlg_return_funcs[i]();
|
dlg_return_funcs[i]();
|
||||||
command(3);
|
command(3); // OK
|
||||||
}
|
}, function(event) {
|
||||||
dlg_form.appendChild(button);
|
command(4); // Cancel
|
||||||
|
});
|
||||||
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);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -733,10 +685,7 @@ mergeInto(LibraryManager.library, {
|
||||||
* associated with it.
|
* associated with it.
|
||||||
*/
|
*/
|
||||||
js_dialog_cleanup: function() {
|
js_dialog_cleanup: function() {
|
||||||
document.body.removeChild(dlg_dimmer);
|
dialog_cleanup();
|
||||||
document.body.removeChild(dlg_form);
|
|
||||||
dlg_dimmer = dlg_form = null;
|
|
||||||
onscreen_canvas.focus();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,72 @@ function disable_menu_item(item, disabledFlag) {
|
||||||
item.className = "";
|
item.className = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dialog-box functions called from both C and JS.
|
||||||
|
function dialog_init(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) + "px";
|
||||||
|
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 = "20px";
|
||||||
|
dlg_form.style.top = (window.innerHeight / 10) + "px";
|
||||||
|
dlg_form.style.left = (window.innerWidth / 6) + "px";
|
||||||
|
dlg_form.style["z-index"] = 100;
|
||||||
|
|
||||||
|
var title = document.createElement("p");
|
||||||
|
title.style.marginTop = "0px";
|
||||||
|
title.appendChild(document.createTextNode(titletext));
|
||||||
|
dlg_form.appendChild(title);
|
||||||
|
|
||||||
|
dlg_return_funcs = [];
|
||||||
|
dlg_next_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function dialog_launch(ok_function, cancel_function) {
|
||||||
|
// Put in the OK and Cancel buttons at the bottom.
|
||||||
|
var button;
|
||||||
|
|
||||||
|
if (ok_function) {
|
||||||
|
button = document.createElement("input");
|
||||||
|
button.type = "button";
|
||||||
|
button.value = "OK";
|
||||||
|
button.onclick = ok_function;
|
||||||
|
dlg_form.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancel_function) {
|
||||||
|
button = document.createElement("input");
|
||||||
|
button.type = "button";
|
||||||
|
button.value = "Cancel";
|
||||||
|
button.onclick = cancel_function;
|
||||||
|
dlg_form.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.appendChild(dlg_dimmer);
|
||||||
|
document.body.appendChild(dlg_form);
|
||||||
|
}
|
||||||
|
|
||||||
|
function dialog_cleanup() {
|
||||||
|
document.body.removeChild(dlg_dimmer);
|
||||||
|
document.body.removeChild(dlg_form);
|
||||||
|
dlg_dimmer = dlg_form = null;
|
||||||
|
onscreen_canvas.focus();
|
||||||
|
}
|
||||||
|
|
||||||
// Init function called from body.onload.
|
// Init function called from body.onload.
|
||||||
function initPuzzle() {
|
function initPuzzle() {
|
||||||
// Construct the off-screen canvas used for double buffering.
|
// Construct the off-screen canvas used for double buffering.
|
||||||
|
|
@ -230,6 +296,58 @@ function initPuzzle() {
|
||||||
command(9);
|
command(9);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 'number' is used for C pointers
|
||||||
|
get_save_file = Module.cwrap('get_save_file', 'number', []);
|
||||||
|
free_save_file = Module.cwrap('free_save_file', 'void', ['number']);
|
||||||
|
load_game = Module.cwrap('load_game', 'void', ['string', 'number']);
|
||||||
|
|
||||||
|
document.getElementById("save").onclick = function(event) {
|
||||||
|
if (dlg_dimmer === null) {
|
||||||
|
var savefile_ptr = get_save_file();
|
||||||
|
var savefile_text = Pointer_stringify(savefile_ptr);
|
||||||
|
free_save_file(savefile_ptr);
|
||||||
|
dialog_init("Download saved-game file");
|
||||||
|
dlg_form.appendChild(document.createTextNode(
|
||||||
|
"Click to download the "));
|
||||||
|
var a = document.createElement("a");
|
||||||
|
a.download = "puzzle.sav";
|
||||||
|
a.href = "data:application/octet-stream," +
|
||||||
|
encodeURIComponent(savefile_text);
|
||||||
|
a.appendChild(document.createTextNode("saved-game file"));
|
||||||
|
dlg_form.appendChild(a);
|
||||||
|
dlg_form.appendChild(document.createTextNode("."));
|
||||||
|
dlg_form.appendChild(document.createElement("br"));
|
||||||
|
dialog_launch(function(event) {
|
||||||
|
dialog_cleanup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.getElementById("load").onclick = function(event) {
|
||||||
|
if (dlg_dimmer === null) {
|
||||||
|
dialog_init("Upload saved-game file");
|
||||||
|
var input = document.createElement("input");
|
||||||
|
input.type = "file";
|
||||||
|
input.multiple = false;
|
||||||
|
dlg_form.appendChild(input);
|
||||||
|
dlg_form.appendChild(document.createElement("br"));
|
||||||
|
dialog_launch(function(event) {
|
||||||
|
if (input.files.length == 1) {
|
||||||
|
var file = input.files.item(0);
|
||||||
|
var reader = new FileReader();
|
||||||
|
reader.addEventListener("loadend", function() {
|
||||||
|
var string = reader.result;
|
||||||
|
load_game(string, string.length);
|
||||||
|
});
|
||||||
|
reader.readAsBinaryString(file);
|
||||||
|
}
|
||||||
|
dialog_cleanup();
|
||||||
|
}, function(event) {
|
||||||
|
dialog_cleanup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
gametypelist = document.getElementById("gametype");
|
gametypelist = document.getElementById("gametype");
|
||||||
gametypesubmenus.push(gametypelist);
|
gametypesubmenus.push(gametypelist);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,10 @@
|
||||||
'_timer_callback',
|
'_timer_callback',
|
||||||
// Callback from button presses in the UI outside the canvas
|
// Callback from button presses in the UI outside the canvas
|
||||||
'_command',
|
'_command',
|
||||||
|
// Game-saving and game-loading functions
|
||||||
|
'_get_save_file',
|
||||||
|
'_free_save_file',
|
||||||
|
'_load_game',
|
||||||
// Callbacks to return values from dialog boxes
|
// Callbacks to return values from dialog boxes
|
||||||
'_dlg_return_sval',
|
'_dlg_return_sval',
|
||||||
'_dlg_return_ival',
|
'_dlg_return_ival',
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ struct font {
|
||||||
*/
|
*/
|
||||||
struct frontend {
|
struct frontend {
|
||||||
GtkWidget *window;
|
GtkWidget *window;
|
||||||
GtkAccelGroup *accelgroup;
|
GtkAccelGroup *dummy_accelgroup;
|
||||||
GtkWidget *area;
|
GtkWidget *area;
|
||||||
GtkWidget *statusbar;
|
GtkWidget *statusbar;
|
||||||
GtkWidget *menubar;
|
GtkWidget *menubar;
|
||||||
|
|
@ -1160,16 +1160,6 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||||
if (!backing_store_ok(fe))
|
if (!backing_store_ok(fe))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
#if !GTK_CHECK_VERSION(2,0,0)
|
|
||||||
/* Gtk 1.2 passes a key event to this function even if it's also
|
|
||||||
* defined as an accelerator.
|
|
||||||
* Gtk 2 doesn't do this, and this function appears not to exist there. */
|
|
||||||
if (fe->accelgroup &&
|
|
||||||
gtk_accel_group_get_entry(fe->accelgroup,
|
|
||||||
event->keyval, event->state))
|
|
||||||
return TRUE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Handle mnemonics. */
|
/* Handle mnemonics. */
|
||||||
if (gtk_window_activate_key(GTK_WINDOW(fe->window), event))
|
if (gtk_window_activate_key(GTK_WINDOW(fe->window), event))
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
@ -1216,6 +1206,8 @@ static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
|
||||||
event->keyval == GDK_KEY_Delete ||
|
event->keyval == GDK_KEY_Delete ||
|
||||||
event->keyval == GDK_KEY_KP_Delete)
|
event->keyval == GDK_KEY_KP_Delete)
|
||||||
keyval = '\177';
|
keyval = '\177';
|
||||||
|
else if ((event->keyval == 'z' || event->keyval == 'Z') && shift && ctrl)
|
||||||
|
keyval = UI_REDO;
|
||||||
else if (event->string[0] && !event->string[1])
|
else if (event->string[0] && !event->string[1])
|
||||||
keyval = (unsigned char)event->string[0];
|
keyval = (unsigned char)event->string[0];
|
||||||
else
|
else
|
||||||
|
|
@ -2348,32 +2340,34 @@ static void menu_about_event(GtkMenuItem *menuitem, gpointer data)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont,
|
static GtkWidget *add_menu_ui_item(
|
||||||
char *text, int key)
|
frontend *fe, GtkContainer *cont, char *text, int action,
|
||||||
|
int accel_key, int accel_keyqual)
|
||||||
{
|
{
|
||||||
GtkWidget *menuitem = gtk_menu_item_new_with_label(text);
|
GtkWidget *menuitem = gtk_menu_item_new_with_label(text);
|
||||||
int keyqual;
|
|
||||||
gtk_container_add(cont, menuitem);
|
gtk_container_add(cont, menuitem);
|
||||||
g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER(key));
|
g_object_set_data(G_OBJECT(menuitem), "user-data",
|
||||||
|
GINT_TO_POINTER(action));
|
||||||
g_signal_connect(G_OBJECT(menuitem), "activate",
|
g_signal_connect(G_OBJECT(menuitem), "activate",
|
||||||
G_CALLBACK(menu_key_event), fe);
|
G_CALLBACK(menu_key_event), fe);
|
||||||
switch (key & ~0x1F) {
|
|
||||||
case 0x00:
|
if (accel_key) {
|
||||||
key += 0x60;
|
/*
|
||||||
keyqual = GDK_CONTROL_MASK;
|
* Display a keyboard accelerator alongside this menu item.
|
||||||
break;
|
* Actually this won't be processed via the usual GTK
|
||||||
case 0x40:
|
* accelerator system, because we add it to a dummy
|
||||||
key += 0x20;
|
* accelerator group which is never actually activated on the
|
||||||
keyqual = GDK_SHIFT_MASK;
|
* main window; this permits back ends to override special
|
||||||
break;
|
* keys like 'n' and 'r' and 'u' in some UI states. So
|
||||||
default:
|
* whatever keystroke we display here will still go to
|
||||||
keyqual = 0;
|
* key_event and be handled in the normal way.
|
||||||
break;
|
*/
|
||||||
|
gtk_widget_add_accelerator(menuitem,
|
||||||
|
"activate", fe->dummy_accelgroup,
|
||||||
|
accel_key, accel_keyqual,
|
||||||
|
GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
|
||||||
}
|
}
|
||||||
gtk_widget_add_accelerator(menuitem,
|
|
||||||
"activate", fe->accelgroup,
|
|
||||||
key, keyqual,
|
|
||||||
GTK_ACCEL_VISIBLE);
|
|
||||||
gtk_widget_show(menuitem);
|
gtk_widget_show(menuitem);
|
||||||
return menuitem;
|
return menuitem;
|
||||||
}
|
}
|
||||||
|
|
@ -2535,8 +2529,11 @@ static frontend *new_window(char *arg, int argtype, char **error)
|
||||||
gtk_container_add(GTK_CONTAINER(fe->window), GTK_WIDGET(vbox));
|
gtk_container_add(GTK_CONTAINER(fe->window), GTK_WIDGET(vbox));
|
||||||
gtk_widget_show(GTK_WIDGET(vbox));
|
gtk_widget_show(GTK_WIDGET(vbox));
|
||||||
|
|
||||||
fe->accelgroup = gtk_accel_group_new();
|
fe->dummy_accelgroup = gtk_accel_group_new();
|
||||||
gtk_window_add_accel_group(GTK_WINDOW(fe->window), fe->accelgroup);
|
/*
|
||||||
|
* Intentionally _not_ added to the window via
|
||||||
|
* gtk_window_add_accel_group; see menu_key_event
|
||||||
|
*/
|
||||||
|
|
||||||
hbox = GTK_BOX(gtk_hbox_new(FALSE, 0));
|
hbox = GTK_BOX(gtk_hbox_new(FALSE, 0));
|
||||||
gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0);
|
gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0);
|
||||||
|
|
@ -2553,7 +2550,7 @@ static frontend *new_window(char *arg, int argtype, char **error)
|
||||||
menu = gtk_menu_new();
|
menu = gtk_menu_new();
|
||||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
|
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu);
|
||||||
|
|
||||||
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "New", 'n');
|
add_menu_ui_item(fe, GTK_CONTAINER(menu), "New", UI_NEWGAME, 'n', 0);
|
||||||
|
|
||||||
menuitem = gtk_menu_item_new_with_label("Restart");
|
menuitem = gtk_menu_item_new_with_label("Restart");
|
||||||
gtk_container_add(GTK_CONTAINER(menu), menuitem);
|
gtk_container_add(GTK_CONTAINER(menu), menuitem);
|
||||||
|
|
@ -2623,8 +2620,8 @@ static frontend *new_window(char *arg, int argtype, char **error)
|
||||||
gtk_widget_show(menuitem);
|
gtk_widget_show(menuitem);
|
||||||
#ifndef STYLUS_BASED
|
#ifndef STYLUS_BASED
|
||||||
add_menu_separator(GTK_CONTAINER(menu));
|
add_menu_separator(GTK_CONTAINER(menu));
|
||||||
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Undo", 'u');
|
add_menu_ui_item(fe, GTK_CONTAINER(menu), "Undo", UI_UNDO, 'u', 0);
|
||||||
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Redo", 'r');
|
add_menu_ui_item(fe, GTK_CONTAINER(menu), "Redo", UI_REDO, 'r', 0);
|
||||||
#endif
|
#endif
|
||||||
if (thegame.can_format_as_text_ever) {
|
if (thegame.can_format_as_text_ever) {
|
||||||
add_menu_separator(GTK_CONTAINER(menu));
|
add_menu_separator(GTK_CONTAINER(menu));
|
||||||
|
|
@ -2646,7 +2643,7 @@ static frontend *new_window(char *arg, int argtype, char **error)
|
||||||
gtk_widget_show(menuitem);
|
gtk_widget_show(menuitem);
|
||||||
}
|
}
|
||||||
add_menu_separator(GTK_CONTAINER(menu));
|
add_menu_separator(GTK_CONTAINER(menu));
|
||||||
add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q');
|
add_menu_ui_item(fe, GTK_CONTAINER(menu), "Exit", UI_QUIT, 'q', 0);
|
||||||
|
|
||||||
menuitem = gtk_menu_item_new_with_mnemonic("_Help");
|
menuitem = gtk_menu_item_new_with_mnemonic("_Help");
|
||||||
gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem);
|
gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem);
|
||||||
|
|
@ -2664,7 +2661,7 @@ static frontend *new_window(char *arg, int argtype, char **error)
|
||||||
#ifdef STYLUS_BASED
|
#ifdef STYLUS_BASED
|
||||||
menuitem=gtk_button_new_with_mnemonic("_Redo");
|
menuitem=gtk_button_new_with_mnemonic("_Redo");
|
||||||
g_object_set_data(G_OBJECT(menuitem), "user-data",
|
g_object_set_data(G_OBJECT(menuitem), "user-data",
|
||||||
GINT_TO_POINTER((int)('r')));
|
GINT_TO_POINTER(UI_REDO));
|
||||||
g_signal_connect(G_OBJECT(menuitem), "clicked",
|
g_signal_connect(G_OBJECT(menuitem), "clicked",
|
||||||
G_CALLBACK(menu_key_event), fe);
|
G_CALLBACK(menu_key_event), fe);
|
||||||
gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0);
|
gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0);
|
||||||
|
|
@ -2672,7 +2669,7 @@ static frontend *new_window(char *arg, int argtype, char **error)
|
||||||
|
|
||||||
menuitem=gtk_button_new_with_mnemonic("_Undo");
|
menuitem=gtk_button_new_with_mnemonic("_Undo");
|
||||||
g_object_set_data(G_OBJECT(menuitem), "user-data",
|
g_object_set_data(G_OBJECT(menuitem), "user-data",
|
||||||
GINT_TO_POINTER((int)('u')));
|
GINT_TO_POINTER(UI_UNDO));
|
||||||
g_signal_connect(G_OBJECT(menuitem), "clicked",
|
g_signal_connect(G_OBJECT(menuitem), "clicked",
|
||||||
G_CALLBACK(menu_key_event), fe);
|
G_CALLBACK(menu_key_event), fe);
|
||||||
gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0);
|
gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0);
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,17 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
my $jspath = "";
|
||||||
|
while ($ARGV[0] =~ /^-/) {
|
||||||
|
my $opt = shift @ARGV;
|
||||||
|
last if $opt eq "--";
|
||||||
|
if ($opt =~ /^--jspath=(.+)$/) {
|
||||||
|
$jspath = $1;
|
||||||
|
} else {
|
||||||
|
die "jspage.pl: unrecognised option '$opt'\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
open my $footerfile, "<", shift @ARGV or die "footer: open: $!\n";
|
open my $footerfile, "<", shift @ARGV or die "footer: open: $!\n";
|
||||||
my $footer = "";
|
my $footer = "";
|
||||||
$footer .= $_ while <$footerfile>;
|
$footer .= $_ while <$footerfile>;
|
||||||
|
|
@ -62,7 +73,7 @@ EOF
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ASCII" />
|
<meta http-equiv="Content-Type" content="text/html; charset=ASCII" />
|
||||||
<title>${puzzlename}, ${unfinishedtitlefragment}from Simon Tatham's Portable Puzzle Collection</title>
|
<title>${puzzlename}, ${unfinishedtitlefragment}from Simon Tatham's Portable Puzzle Collection</title>
|
||||||
<script type="text/javascript" src="${filename}.js"></script>
|
<script type="text/javascript" src="${jspath}${filename}.js"></script>
|
||||||
<style class="text/css">
|
<style class="text/css">
|
||||||
/* Margins and centring on the top-level div for the game menu */
|
/* Margins and centring on the top-level div for the game menu */
|
||||||
#gamemenu { margin-top: 0; margin-bottom: 0.5em; text-align: center }
|
#gamemenu { margin-top: 0; margin-bottom: 0.5em; text-align: center }
|
||||||
|
|
@ -103,6 +114,15 @@ EOF
|
||||||
color: rgba(0,0,0,0.5);
|
color: rgba(0,0,0,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#gamemenu ul li.separator {
|
||||||
|
color: transparent;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#gamemenu ul li.afterseparator {
|
||||||
|
border-left: 1px solid rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
#gamemenu ul li:first-of-type {
|
#gamemenu ul li:first-of-type {
|
||||||
/* Reinstate the left border for the leftmost top-level menu item */
|
/* Reinstate the left border for the leftmost top-level menu item */
|
||||||
border-left: 1px solid rgba(0,0,0,0.3);
|
border-left: 1px solid rgba(0,0,0,0.3);
|
||||||
|
|
@ -196,14 +216,19 @@ ${unfinishedpara}
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<div id="puzzle" style="display: none">
|
<div id="puzzle" style="display: none">
|
||||||
<div id="gamemenu"><ul><li id="new">New game</li
|
<div id="gamemenu"><ul><li>Game...<ul
|
||||||
|
><li id="specific">Enter game ID</li
|
||||||
|
><li id="random">Enter random seed</li
|
||||||
|
><li id="save">Download save file</li
|
||||||
|
><li id="load">Upload save file</li
|
||||||
|
></ul></li
|
||||||
|
><li>Type...<ul id="gametype"></ul></li
|
||||||
|
><li class="separator"></li
|
||||||
|
><li id="new" class="afterseparator">New game</li
|
||||||
><li id="restart">Restart game</li
|
><li id="restart">Restart game</li
|
||||||
><li id="undo">Undo move</li
|
><li id="undo">Undo move</li
|
||||||
><li id="redo">Redo move</li
|
><li id="redo">Redo move</li
|
||||||
><li id="solve">Solve game</li
|
><li id="solve">Solve game</li
|
||||||
><li id="specific">Enter game ID</li
|
|
||||||
><li id="random">Enter random seed</li
|
|
||||||
><li>Select game type<ul id="gametype" class="left"></ul></li
|
|
||||||
></ul></div>
|
></ul></div>
|
||||||
<div align=center>
|
<div align=center>
|
||||||
<div id="resizable" style="position:relative; left:0; top:0">
|
<div id="resizable" style="position:relative; left:0; top:0">
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ static void check_caches(const solver_state* sstate);
|
||||||
{amin, omin, \
|
{amin, omin, \
|
||||||
"Width and height for this grid type must both be at least " #amin, \
|
"Width and height for this grid type must both be at least " #amin, \
|
||||||
"At least one of width and height for this grid type must be at least " #omin,},
|
"At least one of width and height for this grid type must be at least " #omin,},
|
||||||
enum { GRIDLIST(GRID_LOOPYTYPE) };
|
enum { GRIDLIST(GRID_LOOPYTYPE) LOOPY_GRID_DUMMY_TERMINATOR };
|
||||||
static char const *const gridnames[] = { GRIDLIST(GRID_NAME) };
|
static char const *const gridnames[] = { GRIDLIST(GRID_NAME) };
|
||||||
#define GRID_CONFIGS GRIDLIST(GRID_CONFIG)
|
#define GRID_CONFIGS GRIDLIST(GRID_CONFIG)
|
||||||
static grid_type grid_types[] = { GRIDLIST(GRID_GRIDTYPE) };
|
static grid_type grid_types[] = { GRIDLIST(GRID_GRIDTYPE) };
|
||||||
|
|
|
||||||
|
|
@ -590,33 +590,40 @@ static int midend_really_process_key(midend *me, int x, int y, int button)
|
||||||
int type = MOVE, gottype = FALSE, ret = 1;
|
int type = MOVE, gottype = FALSE, ret = 1;
|
||||||
float anim_time;
|
float anim_time;
|
||||||
game_state *s;
|
game_state *s;
|
||||||
char *movestr;
|
char *movestr = NULL;
|
||||||
|
|
||||||
movestr =
|
if (!IS_UI_FAKE_KEY(button)) {
|
||||||
me->ourgame->interpret_move(me->states[me->statepos-1].state,
|
movestr = me->ourgame->interpret_move(
|
||||||
me->ui, me->drawstate, x, y, button);
|
me->states[me->statepos-1].state,
|
||||||
|
me->ui, me->drawstate, x, y, button);
|
||||||
|
}
|
||||||
|
|
||||||
if (!movestr) {
|
if (!movestr) {
|
||||||
if (button == 'n' || button == 'N' || button == '\x0E') {
|
if (button == 'n' || button == 'N' || button == '\x0E' ||
|
||||||
|
button == UI_NEWGAME) {
|
||||||
midend_new_game(me);
|
midend_new_game(me);
|
||||||
midend_redraw(me);
|
midend_redraw(me);
|
||||||
goto done; /* never animate */
|
goto done; /* never animate */
|
||||||
} else if (button == 'u' || button == 'U' ||
|
} else if (button == 'u' || button == 'U' ||
|
||||||
button == '\x1A' || button == '\x1F') {
|
button == '\x1A' || button == '\x1F' ||
|
||||||
|
button == UI_UNDO) {
|
||||||
midend_stop_anim(me);
|
midend_stop_anim(me);
|
||||||
type = me->states[me->statepos-1].movetype;
|
type = me->states[me->statepos-1].movetype;
|
||||||
gottype = TRUE;
|
gottype = TRUE;
|
||||||
if (!midend_undo(me))
|
if (!midend_undo(me))
|
||||||
goto done;
|
goto done;
|
||||||
} else if (button == 'r' || button == 'R' ||
|
} else if (button == 'r' || button == 'R' ||
|
||||||
button == '\x12' || button == '\x19') {
|
button == '\x12' || button == '\x19' ||
|
||||||
|
button == UI_REDO) {
|
||||||
midend_stop_anim(me);
|
midend_stop_anim(me);
|
||||||
if (!midend_redo(me))
|
if (!midend_redo(me))
|
||||||
goto done;
|
goto done;
|
||||||
} else if (button == '\x13' && me->ourgame->can_solve) {
|
} else if ((button == '\x13' || button == UI_SOLVE) &&
|
||||||
|
me->ourgame->can_solve) {
|
||||||
if (midend_solve(me))
|
if (midend_solve(me))
|
||||||
goto done;
|
goto done;
|
||||||
} else if (button == 'q' || button == 'Q' || button == '\x11') {
|
} else if (button == 'q' || button == 'Q' || button == '\x11' ||
|
||||||
|
button == UI_QUIT) {
|
||||||
ret = 0;
|
ret = 0;
|
||||||
goto done;
|
goto done;
|
||||||
} else
|
} else
|
||||||
|
|
@ -2059,6 +2066,8 @@ char *midend_deserialise(midend *me,
|
||||||
me->ourgame->new_drawstate(me->drawing,
|
me->ourgame->new_drawstate(me->drawing,
|
||||||
me->states[me->statepos-1].state);
|
me->states[me->statepos-1].state);
|
||||||
midend_size_new_drawstate(me);
|
midend_size_new_drawstate(me);
|
||||||
|
if (me->game_id_change_notify_function)
|
||||||
|
me->game_id_change_notify_function(me->game_id_change_notify_ctx);
|
||||||
|
|
||||||
ret = NULL; /* success! */
|
ret = NULL; /* success! */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2963,7 +2963,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
|
||||||
float animtime, float flashtime)
|
float animtime, float flashtime)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
int mines, markers, bg;
|
int mines, markers, closed, bg;
|
||||||
int cx = -1, cy = -1, cmoved;
|
int cx = -1, cy = -1, cmoved;
|
||||||
|
|
||||||
if (flashtime) {
|
if (flashtime) {
|
||||||
|
|
@ -3013,13 +3013,15 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now draw the tiles. Also in this loop, count up the number
|
* Now draw the tiles. Also in this loop, count up the number
|
||||||
* of mines and mine markers.
|
* of mines, mine markers, and closed squares.
|
||||||
*/
|
*/
|
||||||
mines = markers = 0;
|
mines = markers = closed = 0;
|
||||||
for (y = 0; y < ds->h; y++)
|
for (y = 0; y < ds->h; y++)
|
||||||
for (x = 0; x < ds->w; x++) {
|
for (x = 0; x < ds->w; x++) {
|
||||||
int v = state->grid[y*ds->w+x], cc = 0;
|
int v = state->grid[y*ds->w+x], cc = 0;
|
||||||
|
|
||||||
|
if (v < 0)
|
||||||
|
closed++;
|
||||||
if (v == -1)
|
if (v == -1)
|
||||||
markers++;
|
markers++;
|
||||||
if (state->layout->mines && state->layout->mines[y*ds->w+x])
|
if (state->layout->mines && state->layout->mines[y*ds->w+x])
|
||||||
|
|
@ -3078,7 +3080,42 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
|
||||||
else
|
else
|
||||||
sprintf(statusbar, "COMPLETED!");
|
sprintf(statusbar, "COMPLETED!");
|
||||||
} else {
|
} else {
|
||||||
|
int safe_closed = closed - mines;
|
||||||
sprintf(statusbar, "Marked: %d / %d", markers, mines);
|
sprintf(statusbar, "Marked: %d / %d", markers, mines);
|
||||||
|
if (safe_closed > 0 && safe_closed <= 9) {
|
||||||
|
/*
|
||||||
|
* In the situation where there's a very small number
|
||||||
|
* of _non_-mine squares left unopened, it's helpful
|
||||||
|
* to mention that number in the status line, to save
|
||||||
|
* the player from having to count it up
|
||||||
|
* painstakingly. This is particularly important if
|
||||||
|
* the player has turned up the mine density to the
|
||||||
|
* point where game generation resorts to its weird
|
||||||
|
* pathological fallback of a very dense mine area
|
||||||
|
* with a clearing in the middle, because that often
|
||||||
|
* leads to a deduction you can only make by knowing
|
||||||
|
* that there is (say) exactly one non-mine square to
|
||||||
|
* find, and it's a real pain to have to count up two
|
||||||
|
* large numbers of squares and subtract them to get
|
||||||
|
* that value of 1.
|
||||||
|
*
|
||||||
|
* The threshold value of 8 for displaying this
|
||||||
|
* information is because that's the largest number of
|
||||||
|
* non-mine squares that might conceivably fit around
|
||||||
|
* a single central square, and the most likely way to
|
||||||
|
* _use_ this information is to observe that if all
|
||||||
|
* the remaining safe squares are adjacent to _this_
|
||||||
|
* square then everything else can be immediately
|
||||||
|
* flagged as a mine.
|
||||||
|
*/
|
||||||
|
if (safe_closed == 1) {
|
||||||
|
sprintf(statusbar + strlen(statusbar),
|
||||||
|
" (1 safe square remains)");
|
||||||
|
} else {
|
||||||
|
sprintf(statusbar + strlen(statusbar),
|
||||||
|
" (%d safe squares remain)", safe_closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (ui->deaths)
|
if (ui->deaths)
|
||||||
sprintf(statusbar + strlen(statusbar),
|
sprintf(statusbar + strlen(statusbar),
|
||||||
|
|
|
||||||
|
|
@ -375,7 +375,7 @@ void copy_left_justified(char *buf, size_t sz, const char *str)
|
||||||
/* another kludge for platforms without %g support in *printf() */
|
/* another kludge for platforms without %g support in *printf() */
|
||||||
int ftoa(char *buf, float f)
|
int ftoa(char *buf, float f)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d.%06d", (int)f, (int)((f - (int)f)*1e6));
|
return sprintf(buf, "%d.%06d", (int)f, abs((int)((f - (int)f)*1e6)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* vim: set shiftwidth=4 tabstop=8: */
|
/* vim: set shiftwidth=4 tabstop=8: */
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ sub mfval($) {
|
||||||
# Returns true if the argument is a known makefile type. Otherwise,
|
# Returns true if the argument is a known makefile type. Otherwise,
|
||||||
# prints a warning and returns false;
|
# prints a warning and returns false;
|
||||||
if (grep { $type eq $_ }
|
if (grep { $type eq $_ }
|
||||||
("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc")) {
|
("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc","clangcl")) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
warn "$.:unknown makefile type '$type'\n";
|
warn "$.:unknown makefile type '$type'\n";
|
||||||
|
|
@ -503,6 +503,151 @@ $orig_dir = cwd;
|
||||||
|
|
||||||
# Now we're ready to output the actual Makefiles.
|
# Now we're ready to output the actual Makefiles.
|
||||||
|
|
||||||
|
if (defined $makefiles{'clangcl'}) {
|
||||||
|
$mftyp = 'clangcl';
|
||||||
|
$dirpfx = &dirpfx($makefiles{'clangcl'}, "/");
|
||||||
|
|
||||||
|
##-- Makefile for cross-compiling using clang-cl, lld-link, and
|
||||||
|
## MinGW's windres for resource compilation.
|
||||||
|
#
|
||||||
|
# This makefile allows a complete Linux-based cross-compile, but
|
||||||
|
# using the real Visual Studio header files and libraries. In
|
||||||
|
# order to run it, you will need:
|
||||||
|
#
|
||||||
|
# - MinGW windres on your PATH.
|
||||||
|
# * On Ubuntu as of 16.04, you can apt-get install
|
||||||
|
# binutils-mingw-w64-x86-64 and binutils-mingw-w64-i686
|
||||||
|
# which will provide (respectively) 64- and 32-bit versions,
|
||||||
|
# under the names to which RCCMD is defined below.
|
||||||
|
# - clang-cl and lld-link on your PATH.
|
||||||
|
# * I built these from the up-to-date LLVM project trunk git
|
||||||
|
# repositories, as of 2017-02-05.
|
||||||
|
# - case-mashed copies of the Visual Studio include directories.
|
||||||
|
# * On a real VS installation, run vcvars32.bat and look at
|
||||||
|
# the resulting value of %INCLUDE%. Take a full copy of each
|
||||||
|
# of those directories, and inside the copy, for each
|
||||||
|
# include file that has an uppercase letter in its name,
|
||||||
|
# make a lowercased symlink to it. Additionally, one of the
|
||||||
|
# directories will contain files called driverspecs.h and
|
||||||
|
# specstrings.h, and those will need symlinks called
|
||||||
|
# DriverSpecs.h and SpecStrings.h.
|
||||||
|
# * Now, on Linux, define the environment variable INCLUDE to
|
||||||
|
# be a list, separated by *semicolons* (in the Windows
|
||||||
|
# style), of those directories, but before all of them you
|
||||||
|
# must also include lib/clang/5.0.0/include from the clang
|
||||||
|
# installation area (which contains in particular a
|
||||||
|
# clang-compatible stdarg.h overriding the Visual Studio
|
||||||
|
# one).
|
||||||
|
# - similarly case-mashed copies of the library directories.
|
||||||
|
# * Again, on a real VS installation, run vcvars32 or
|
||||||
|
# vcvarsx86_amd64 (as appropriate), look at %LIB%, make a
|
||||||
|
# copy of each directory, and provide symlinks within that
|
||||||
|
# directory so that all the files can be opened as
|
||||||
|
# lowercase.
|
||||||
|
# * Then set LIB to be a semicolon-separated list of those
|
||||||
|
# directories (but you'll need to change which set of
|
||||||
|
# directories depending on whether you want to do a 32-bit
|
||||||
|
# or 64-bit build).
|
||||||
|
# - for a 64-bit build, set 'Platform=x64' in the environment as
|
||||||
|
# well, or else on the make command line.
|
||||||
|
# * This is a variable understood only by this makefile - none
|
||||||
|
# of the tools we invoke will know it - but it's consistent
|
||||||
|
# with the way the VS scripts like vcvarsx86_amd64.bat set
|
||||||
|
# things up, and since the environment has to change
|
||||||
|
# _anyway_ between 32- and 64-bit builds (different set of
|
||||||
|
# paths in $LIB) it's reasonable to have the choice of
|
||||||
|
# compilation target driven by another environment variable
|
||||||
|
# set in parallel with that one.
|
||||||
|
# - for older versions of the VS libraries you may also have to
|
||||||
|
# set EXTRA_console and/or EXTRA_windows to the name of an
|
||||||
|
# object file manually extracted from one of those libraries.
|
||||||
|
# * This is because old VS seems to manage its startup code by
|
||||||
|
# having libcmt.lib contain lots of *crt0.obj objects, one
|
||||||
|
# for each possible user entry point (main, WinMain and the
|
||||||
|
# wide-char versions of both), of which the linker arranges
|
||||||
|
# to include the right one by special-case code. But lld
|
||||||
|
# only seems to mimic half of that code - it does include
|
||||||
|
# the right crt0 object, but it doesn't also deliberately
|
||||||
|
# _avoid_ including the _wrong_ ones, and since all those
|
||||||
|
# objects define a common set of global symbols for other
|
||||||
|
# parts of the library to use, lld may well select an
|
||||||
|
# arbitrary one of them the first time it sees a reference
|
||||||
|
# to one of those global symbols, and then later also select
|
||||||
|
# the _right_ one for the application's entry point, causing
|
||||||
|
# a multiple-definitions crash.
|
||||||
|
# * So the workaround is to explicitly include the right
|
||||||
|
# *crt0.obj file on the linker command line before lld even
|
||||||
|
# begins searching libraries. Hence, for a console
|
||||||
|
# application, you might extract crt0.obj from the library
|
||||||
|
# in question and set EXTRA_console=crt0.obj, and for a GUI
|
||||||
|
# application, do the same with wincrt0.obj. Then this
|
||||||
|
# makefile will include the right one of those objects
|
||||||
|
# alongside the matching /subsystem linker option.
|
||||||
|
|
||||||
|
open OUT, ">$makefiles{'clangcl'}"; select OUT;
|
||||||
|
print
|
||||||
|
"# Makefile for cross-compiling $project_name using clang-cl, lld-link,\n".
|
||||||
|
"# and MinGW's windres, using GNU make on Linux.\n".
|
||||||
|
"#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
|
||||||
|
"# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
|
||||||
|
print $help;
|
||||||
|
print
|
||||||
|
"\n".
|
||||||
|
"CCCMD = clang-cl\n".
|
||||||
|
"ifeq (\$(Platform),x64)\n".
|
||||||
|
"CCTARGET = x86_64-pc-windows-msvc18.0.0\n".
|
||||||
|
"RCCMD = x86_64-w64-mingw32-windres\n".
|
||||||
|
"else\n".
|
||||||
|
"CCTARGET = i386-pc-windows-msvc18.0.0\n".
|
||||||
|
"RCCMD = i686-w64-mingw32-windres\n".
|
||||||
|
"endif\n".
|
||||||
|
"CC = \$(CCCMD) --target=\$(CCTARGET)\n".
|
||||||
|
&splitline("RC = \$(RCCMD) --preprocessor=\$(CCCMD) ".
|
||||||
|
"--preprocessor-arg=/TC --preprocessor-arg=/E")."\n".
|
||||||
|
"LD = lld-link\n".
|
||||||
|
"\n".
|
||||||
|
"# C compilation flags\n".
|
||||||
|
&splitline("CFLAGS = /nologo /W3 /O1 " .
|
||||||
|
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
|
||||||
|
" /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401 ".
|
||||||
|
"/D_CRT_SECURE_NO_WARNINGS")."\n".
|
||||||
|
"LFLAGS = /incremental:no /dynamicbase /nxcompat\n".
|
||||||
|
&splitline("RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs).
|
||||||
|
" -DWIN32 -D_WIN32 -DWINVER=0x0400 --define MINGW32_FIX=1")."\n".
|
||||||
|
"\n".
|
||||||
|
"\n";
|
||||||
|
print &splitline("all:" . join "", map { " \$(BUILDDIR)$_.exe" } &progrealnames("G:C"));
|
||||||
|
print "\n\n";
|
||||||
|
foreach $p (&prognames("G:C")) {
|
||||||
|
($prog, $type) = split ",", $p;
|
||||||
|
$objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", undef);
|
||||||
|
print &splitline("\$(BUILDDIR)$prog.exe: " . $objstr), "\n";
|
||||||
|
|
||||||
|
$objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", "X.lib");
|
||||||
|
$subsys = ($type eq "G") ? "windows" : "console";
|
||||||
|
print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ".
|
||||||
|
"/out:\$(BUILDDIR)$prog.exe ".
|
||||||
|
"/lldmap:\$(BUILDDIR)$prog.map ".
|
||||||
|
"/subsystem:$subsys\$(SUBSYSVER) ".
|
||||||
|
"\$(EXTRA_$subsys) $objstr")."\n\n";
|
||||||
|
}
|
||||||
|
foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", $dirpfx, "/", "vc")) {
|
||||||
|
print &splitline(sprintf("%s: %s", $d->{obj},
|
||||||
|
join " ", @{$d->{deps}})), "\n";
|
||||||
|
if ($d->{obj} =~ /\.res$/) {
|
||||||
|
print "\t\$(RC) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n";
|
||||||
|
} else {
|
||||||
|
$deflist = join "", map { " /D$_" } @{$d->{defs}};
|
||||||
|
print "\t\$(CC) /Fo\$(BUILDDIR)".$d->{obj}." \$(COMPAT) \$(CFLAGS) \$(XFLAGS)$deflist /c \$<\n\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "\nclean:\n".
|
||||||
|
&splitline("\trm -f \$(BUILDDIR)*.obj \$(BUILDDIR)*.exe ".
|
||||||
|
"\$(BUILDDIR)*.res \$(BUILDDIR)*.map ".
|
||||||
|
"\$(BUILDDIR)*.exe.manifest")."\n";
|
||||||
|
select STDOUT; close OUT;
|
||||||
|
}
|
||||||
|
|
||||||
if (defined $makefiles{'cygwin'}) {
|
if (defined $makefiles{'cygwin'}) {
|
||||||
$mftyp = 'cygwin';
|
$mftyp = 'cygwin';
|
||||||
$dirpfx = &dirpfx($makefiles{'cygwin'}, "/");
|
$dirpfx = &dirpfx($makefiles{'cygwin'}, "/");
|
||||||
|
|
|
||||||
|
|
@ -305,10 +305,34 @@ static int get_config(frontend *fe, int which)
|
||||||
return fe->cfgret;
|
return fe->cfgret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int jcallback_menu_key_event(int key)
|
int jcallback_newgame_event(void)
|
||||||
{
|
{
|
||||||
frontend *fe = (frontend *)_fe;
|
frontend *fe = (frontend *)_fe;
|
||||||
if (!midend_process_key(fe->me, 0, 0, key))
|
if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME))
|
||||||
|
return 42;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jcallback_undo_event(void)
|
||||||
|
{
|
||||||
|
frontend *fe = (frontend *)_fe;
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, UI_UNDO))
|
||||||
|
return 42;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jcallback_redo_event(void)
|
||||||
|
{
|
||||||
|
frontend *fe = (frontend *)_fe;
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, UI_REDO))
|
||||||
|
return 42;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int jcallback_quit_event(void)
|
||||||
|
{
|
||||||
|
frontend *fe = (frontend *)_fe;
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, UI_QUIT))
|
||||||
return 42;
|
return 42;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -687,6 +687,10 @@ struct frontend {
|
||||||
if (c >= '0' && c <= '9' && ([ev modifierFlags] & NSNumericPadKeyMask))
|
if (c >= '0' && c <= '9' && ([ev modifierFlags] & NSNumericPadKeyMask))
|
||||||
c |= MOD_NUM_KEYPAD;
|
c |= MOD_NUM_KEYPAD;
|
||||||
|
|
||||||
|
if (c == 26 &&
|
||||||
|
!((NSShiftKeyMask | NSControlKeyMask) & ~[ev modifierFlags]))
|
||||||
|
c = UI_REDO;
|
||||||
|
|
||||||
[self processKey:c];
|
[self processKey:c];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -735,7 +739,7 @@ struct frontend {
|
||||||
|
|
||||||
- (void)newGame:(id)sender
|
- (void)newGame:(id)sender
|
||||||
{
|
{
|
||||||
[self processKey:'n'];
|
[self processKey:UI_NEWGAME];
|
||||||
}
|
}
|
||||||
- (void)restartGame:(id)sender
|
- (void)restartGame:(id)sender
|
||||||
{
|
{
|
||||||
|
|
@ -809,11 +813,11 @@ struct frontend {
|
||||||
}
|
}
|
||||||
- (void)undoMove:(id)sender
|
- (void)undoMove:(id)sender
|
||||||
{
|
{
|
||||||
[self processKey:'u'];
|
[self processKey:UI_UNDO];
|
||||||
}
|
}
|
||||||
- (void)redoMove:(id)sender
|
- (void)redoMove:(id)sender
|
||||||
{
|
{
|
||||||
[self processKey:'r'&0x1F];
|
[self processKey:UI_REDO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)copy:(id)sender
|
- (void)copy:(id)sender
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,18 @@ static void generate(random_state *rs, int w, int h, unsigned char *retgrid)
|
||||||
fgrid2 = snewn(w*h, float);
|
fgrid2 = snewn(w*h, float);
|
||||||
memcpy(fgrid2, fgrid, w*h*sizeof(float));
|
memcpy(fgrid2, fgrid, w*h*sizeof(float));
|
||||||
qsort(fgrid2, w*h, sizeof(float), float_compare);
|
qsort(fgrid2, w*h, sizeof(float), float_compare);
|
||||||
threshold = fgrid2[w*h/2];
|
/* Choose a threshold that makes half the pixels black. In case of
|
||||||
|
* an odd number of pixels, select randomly between just under and
|
||||||
|
* just over half. */
|
||||||
|
{
|
||||||
|
int index = w * h / 2;
|
||||||
|
if (w & h & 1)
|
||||||
|
index += random_upto(rs, 2);
|
||||||
|
if (index < w*h)
|
||||||
|
threshold = fgrid2[index];
|
||||||
|
else
|
||||||
|
threshold = fgrid2[w*h-1] + 1;
|
||||||
|
}
|
||||||
sfree(fgrid2);
|
sfree(fgrid2);
|
||||||
|
|
||||||
for (i = 0; i < h; i++) {
|
for (i = 0; i < h; i++) {
|
||||||
|
|
@ -448,6 +459,8 @@ static int do_row(unsigned char *known, unsigned char *deduced,
|
||||||
|
|
||||||
if (rowlen == 0) {
|
if (rowlen == 0) {
|
||||||
memset(deduced, DOT, len);
|
memset(deduced, DOT, len);
|
||||||
|
} else if (rowlen == 1 && data[0] == len) {
|
||||||
|
memset(deduced, BLOCK, len);
|
||||||
} else {
|
} else {
|
||||||
do_recurse(known, deduced, row, minpos_done, maxpos_done, minpos_ok,
|
do_recurse(known, deduced, row, minpos_done, maxpos_done, minpos_ok,
|
||||||
maxpos_ok, data, len, freespace, 0, 0);
|
maxpos_ok, data, len, freespace, 0, 0);
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,15 @@ enum {
|
||||||
CURSOR_RIGHT,
|
CURSOR_RIGHT,
|
||||||
CURSOR_SELECT,
|
CURSOR_SELECT,
|
||||||
CURSOR_SELECT2,
|
CURSOR_SELECT2,
|
||||||
|
/* UI_* are special keystrokes generated by front ends in response
|
||||||
|
* to menu actions, never passed to back ends */
|
||||||
|
UI_LOWER_BOUND,
|
||||||
|
UI_QUIT,
|
||||||
|
UI_NEWGAME,
|
||||||
|
UI_SOLVE,
|
||||||
|
UI_UNDO,
|
||||||
|
UI_REDO,
|
||||||
|
UI_UPPER_BOUND,
|
||||||
|
|
||||||
/* made smaller because of 'limited range of datatype' errors. */
|
/* made smaller because of 'limited range of datatype' errors. */
|
||||||
MOD_CTRL = 0x1000,
|
MOD_CTRL = 0x1000,
|
||||||
|
|
@ -64,6 +73,7 @@ enum {
|
||||||
#define IS_CURSOR_MOVE(m) ( (m) == CURSOR_UP || (m) == CURSOR_DOWN || \
|
#define IS_CURSOR_MOVE(m) ( (m) == CURSOR_UP || (m) == CURSOR_DOWN || \
|
||||||
(m) == CURSOR_RIGHT || (m) == CURSOR_LEFT )
|
(m) == CURSOR_RIGHT || (m) == CURSOR_LEFT )
|
||||||
#define IS_CURSOR_SELECT(m) ( (m) == CURSOR_SELECT || (m) == CURSOR_SELECT2)
|
#define IS_CURSOR_SELECT(m) ( (m) == CURSOR_SELECT || (m) == CURSOR_SELECT2)
|
||||||
|
#define IS_UI_FAKE_KEY(m) ( (m) > UI_LOWER_BOUND && (m) < UI_UPPER_BOUND )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flags in the back end's `flags' word.
|
* Flags in the back end's `flags' word.
|
||||||
|
|
|
||||||
|
|
@ -1718,7 +1718,10 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
|
||||||
#define TILE_SIZE (ds->sz6*6)
|
#define TILE_SIZE (ds->sz6*6)
|
||||||
|
|
||||||
#define BORDER (TILE_SIZE/8)
|
#define BORDER (TILE_SIZE/8)
|
||||||
#define BORDER_WIDTH (max(TILE_SIZE / 32, 1))
|
#define LINE_THICK (TILE_SIZE/16)
|
||||||
|
#define GRID_LINE_TL (ds->grid_line_tl)
|
||||||
|
#define GRID_LINE_BR (ds->grid_line_br)
|
||||||
|
#define GRID_LINE_ALL (ds->grid_line_all)
|
||||||
|
|
||||||
#define COORD(x) ( (x+1) * TILE_SIZE + BORDER )
|
#define COORD(x) ( (x+1) * TILE_SIZE + BORDER )
|
||||||
#define CENTERED_COORD(x) ( COORD(x) + TILE_SIZE/2 )
|
#define CENTERED_COORD(x) ( COORD(x) + TILE_SIZE/2 )
|
||||||
|
|
@ -1738,7 +1741,7 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
|
||||||
#define DS_CSHIFT 20 /* R/U/L/D shift, for cursor-on-edge */
|
#define DS_CSHIFT 20 /* R/U/L/D shift, for cursor-on-edge */
|
||||||
|
|
||||||
struct game_drawstate {
|
struct game_drawstate {
|
||||||
int sz6;
|
int sz6, grid_line_all, grid_line_tl, grid_line_br;
|
||||||
int started;
|
int started;
|
||||||
|
|
||||||
int w, h, sz;
|
int w, h, sz;
|
||||||
|
|
@ -2118,7 +2121,6 @@ static void game_compute_size(const game_params *params, int tilesize,
|
||||||
int sz6;
|
int sz6;
|
||||||
} ads, *ds = &ads;
|
} ads, *ds = &ads;
|
||||||
ads.sz6 = tilesize/6;
|
ads.sz6 = tilesize/6;
|
||||||
|
|
||||||
*x = (params->w+2) * TILE_SIZE + 2 * BORDER;
|
*x = (params->w+2) * TILE_SIZE + 2 * BORDER;
|
||||||
*y = (params->h+2) * TILE_SIZE + 2 * BORDER;
|
*y = (params->h+2) * TILE_SIZE + 2 * BORDER;
|
||||||
}
|
}
|
||||||
|
|
@ -2127,6 +2129,9 @@ static void game_set_size(drawing *dr, game_drawstate *ds,
|
||||||
const game_params *params, int tilesize)
|
const game_params *params, int tilesize)
|
||||||
{
|
{
|
||||||
ds->sz6 = tilesize/6;
|
ds->sz6 = tilesize/6;
|
||||||
|
ds->grid_line_all = max(LINE_THICK, 1);
|
||||||
|
ds->grid_line_br = ds->grid_line_all / 2;
|
||||||
|
ds->grid_line_tl = ds->grid_line_all - ds->grid_line_br;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -2346,14 +2351,13 @@ static void draw_square(drawing *dr, game_drawstate *ds,
|
||||||
/* Clip to the grid square. */
|
/* Clip to the grid square. */
|
||||||
clip(dr, ox, oy, TILE_SIZE, TILE_SIZE);
|
clip(dr, ox, oy, TILE_SIZE, TILE_SIZE);
|
||||||
|
|
||||||
/* Clear the square. */
|
/* Clear the square so that it's got an appropriately-sized border
|
||||||
|
* in COL_GRID and a central area in the right background colour. */
|
||||||
best_bits((flags & DS_TRACK) == DS_TRACK,
|
best_bits((flags & DS_TRACK) == DS_TRACK,
|
||||||
(flags_drag & DS_TRACK) == DS_TRACK, &bg);
|
(flags_drag & DS_TRACK) == DS_TRACK, &bg);
|
||||||
draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, bg);
|
draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, COL_GRID);
|
||||||
|
draw_rect(dr, ox + GRID_LINE_TL, oy + GRID_LINE_TL,
|
||||||
/* Draw outline of grid square */
|
TILE_SIZE - GRID_LINE_ALL, TILE_SIZE - GRID_LINE_ALL, bg);
|
||||||
draw_line(dr, ox, oy, COORD(x+1), oy, COL_GRID);
|
|
||||||
draw_line(dr, ox, oy, ox, COORD(y+1), COL_GRID);
|
|
||||||
|
|
||||||
/* More outlines for clue squares. */
|
/* More outlines for clue squares. */
|
||||||
if (flags & DS_CURSOR) {
|
if (flags & DS_CURSOR) {
|
||||||
|
|
@ -2389,8 +2393,8 @@ static void draw_square(drawing *dr, game_drawstate *ds,
|
||||||
(flags_drag & DS_NOTRACK) == DS_NOTRACK, &c);
|
(flags_drag & DS_NOTRACK) == DS_NOTRACK, &c);
|
||||||
if (flags_best) {
|
if (flags_best) {
|
||||||
off = HALFSZ/2;
|
off = HALFSZ/2;
|
||||||
draw_line(dr, cx - off, cy - off, cx + off, cy + off, c);
|
draw_thick_line(dr, LINE_THICK, cx - off, cy - off, cx + off, cy + off, c);
|
||||||
draw_line(dr, cx - off, cy + off, cx + off, cy - off, c);
|
draw_thick_line(dr, LINE_THICK, cx - off, cy + off, cx + off, cy - off, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
c = COL_TRACK;
|
c = COL_TRACK;
|
||||||
|
|
@ -2404,8 +2408,8 @@ static void draw_square(drawing *dr, game_drawstate *ds,
|
||||||
cx += (d == R) ? t2 : (d == L) ? -t2 : 0;
|
cx += (d == R) ? t2 : (d == L) ? -t2 : 0;
|
||||||
cy += (d == D) ? t2 : (d == U) ? -t2 : 0;
|
cy += (d == D) ? t2 : (d == U) ? -t2 : 0;
|
||||||
|
|
||||||
draw_line(dr, cx - off, cy - off, cx + off, cy + off, c);
|
draw_thick_line(dr, LINE_THICK, cx - off, cy - off, cx + off, cy + off, c);
|
||||||
draw_line(dr, cx - off, cy + off, cx + off, cy - off, c);
|
draw_thick_line(dr, LINE_THICK, cx - off, cy + off, cx + off, cy - off, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2426,12 +2430,14 @@ static void draw_clue(drawing *dr, game_drawstate *ds, int w, int clue, int i, i
|
||||||
cy = CENTERED_COORD(i-w);
|
cy = CENTERED_COORD(i-w);
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_rect(dr, cx - tsz + BORDER, cy - tsz + BORDER,
|
draw_rect(dr, cx - tsz + GRID_LINE_TL, cy - tsz + GRID_LINE_TL,
|
||||||
TILE_SIZE - BORDER, TILE_SIZE - BORDER, COL_BACKGROUND);
|
TILE_SIZE - GRID_LINE_ALL, TILE_SIZE - GRID_LINE_ALL,
|
||||||
|
COL_BACKGROUND);
|
||||||
sprintf(buf, "%d", clue);
|
sprintf(buf, "%d", clue);
|
||||||
draw_text(dr, cx, cy, FONT_VARIABLE, tsz, ALIGN_VCENTRE|ALIGN_HCENTRE,
|
draw_text(dr, cx, cy, FONT_VARIABLE, tsz, ALIGN_VCENTRE|ALIGN_HCENTRE,
|
||||||
col, buf);
|
col, buf);
|
||||||
draw_update(dr, cx - tsz, cy - tsz, TILE_SIZE, TILE_SIZE);
|
draw_update(dr, cx - tsz + GRID_LINE_TL, cy - tsz + GRID_LINE_TL,
|
||||||
|
TILE_SIZE - GRID_LINE_ALL, TILE_SIZE - GRID_LINE_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_loop_ends(drawing *dr, game_drawstate *ds,
|
static void draw_loop_ends(drawing *dr, game_drawstate *ds,
|
||||||
|
|
@ -2498,8 +2504,9 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst
|
||||||
|
|
||||||
draw_loop_ends(dr, ds, state, COL_CLUE);
|
draw_loop_ends(dr, ds, state, COL_CLUE);
|
||||||
|
|
||||||
draw_line(dr, COORD(ds->w), COORD(0), COORD(ds->w), COORD(ds->h), COL_GRID);
|
draw_rect(dr, COORD(0) - GRID_LINE_BR, COORD(0) - GRID_LINE_BR,
|
||||||
draw_line(dr, COORD(0), COORD(ds->h), COORD(ds->w), COORD(ds->h), COL_GRID);
|
ds->w * TILE_SIZE + GRID_LINE_ALL,
|
||||||
|
ds->h * TILE_SIZE + GRID_LINE_ALL, COL_GRID);
|
||||||
|
|
||||||
draw_update(dr, 0, 0, (w+2)*TILE_SIZE + 2*BORDER, (h+2)*TILE_SIZE + 2*BORDER);
|
draw_update(dr, 0, 0, (w+2)*TILE_SIZE + 2*BORDER, (h+2)*TILE_SIZE + 2*BORDER);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ while (<$desc>) {
|
||||||
'<span class="puzzle"><table>'.
|
'<span class="puzzle"><table>'.
|
||||||
'<tr><th align="center">%s</th></tr>'.
|
'<tr><th align="center">%s</th></tr>'.
|
||||||
'<tr><td align="center">'.
|
'<tr><td align="center">'.
|
||||||
'<img style="margin: 0.5em" alt="" title="%s" width=150 height=150 border=0 src="%s-web.png" />'.
|
'<a href="js/%s.html"><img style="margin: 0.5em" alt="" title="%s" width=150 height=150 border=0 src="%s-web.png" /></a>'.
|
||||||
'</td></tr>'.
|
'</td></tr>'.
|
||||||
'<tr><td align="center" style="font-size: 70%%"><code>[</code>'.
|
'<tr><td align="center" style="font-size: 70%%"><code>[</code>'.
|
||||||
' <a href="java/%s.html">java</a> '.
|
' <a href="java/%s.html">java</a> '.
|
||||||
|
|
@ -41,6 +41,7 @@ while (<$desc>) {
|
||||||
'<tr><td align="center">%s</td></tr></table></span>'.
|
'<tr><td align="center">%s</td></tr></table></span>'.
|
||||||
"\n",
|
"\n",
|
||||||
encode_entities($displayname),
|
encode_entities($displayname),
|
||||||
|
encode_entities($id),
|
||||||
encode_entities($description),
|
encode_entities($description),
|
||||||
encode_entities($id),
|
encode_entities($id),
|
||||||
encode_entities($id),
|
encode_entities($id),
|
||||||
|
|
|
||||||
|
|
@ -1545,7 +1545,7 @@ static frontend *frontend_new(HINSTANCE inst)
|
||||||
fe->statusbar = NULL;
|
fe->statusbar = NULL;
|
||||||
fe->bitmap = NULL;
|
fe->bitmap = NULL;
|
||||||
|
|
||||||
SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe);
|
SetWindowLongPtr(fe->hwnd, GWLP_USERDATA, (LONG_PTR)fe);
|
||||||
|
|
||||||
return fe;
|
return fe;
|
||||||
}
|
}
|
||||||
|
|
@ -1992,7 +1992,7 @@ static void make_dialog_full_screen(HWND hwnd)
|
||||||
static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
|
static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg,
|
||||||
WPARAM wParam, LPARAM lParam)
|
WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA);
|
frontend *fe = (frontend *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||||
|
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
|
|
@ -2249,7 +2249,7 @@ static void create_config_controls(frontend * fe)
|
||||||
static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
|
static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
|
||||||
WPARAM wParam, LPARAM lParam)
|
WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA);
|
frontend *fe = (frontend *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||||
config_item *i;
|
config_item *i;
|
||||||
struct cfg_aux *j;
|
struct cfg_aux *j;
|
||||||
|
|
||||||
|
|
@ -2260,7 +2260,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg,
|
||||||
char *title;
|
char *title;
|
||||||
|
|
||||||
fe = (frontend *) lParam;
|
fe = (frontend *) lParam;
|
||||||
SetWindowLong(hwnd, GWL_USERDATA, lParam);
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
|
||||||
fe->cfgbox = hwnd;
|
fe->cfgbox = hwnd;
|
||||||
|
|
||||||
fe->cfg = frontend_get_config(fe, fe->cfg_which, &title);
|
fe->cfg = frontend_get_config(fe, fe->cfg_which, &title);
|
||||||
|
|
@ -2479,8 +2479,8 @@ static void about(frontend *fe)
|
||||||
|
|
||||||
SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE);
|
SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE);
|
||||||
|
|
||||||
SetWindowLong(fe->cfgbox, GWL_USERDATA, (LONG)fe);
|
SetWindowLongPtr(fe->cfgbox, GWLP_USERDATA, (LONG_PTR)fe);
|
||||||
SetWindowLong(fe->cfgbox, DWL_DLGPROC, (LONG)AboutDlgProc);
|
SetWindowLongPtr(fe->cfgbox, DWLP_DLGPROC, (LONG_PTR)AboutDlgProc);
|
||||||
|
|
||||||
id = 1000;
|
id = 1000;
|
||||||
y = height/2;
|
y = height/2;
|
||||||
|
|
@ -2660,8 +2660,8 @@ static int get_config(frontend *fe, int which)
|
||||||
|
|
||||||
SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE);
|
SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE);
|
||||||
|
|
||||||
SetWindowLong(fe->cfgbox, GWL_USERDATA, (LONG)fe);
|
SetWindowLongPtr(fe->cfgbox, GWLP_USERDATA, (LONG_PTR)fe);
|
||||||
SetWindowLong(fe->cfgbox, DWL_DLGPROC, (LONG)ConfigDlgProc);
|
SetWindowLongPtr(fe->cfgbox, DWLP_DLGPROC, (LONG_PTR)ConfigDlgProc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Count the controls so we can allocate cfgaux.
|
* Count the controls so we can allocate cfgaux.
|
||||||
|
|
@ -2975,7 +2975,7 @@ static int is_alt_pressed(void)
|
||||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||||
WPARAM wParam, LPARAM lParam)
|
WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA);
|
frontend *fe = (frontend *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
||||||
int cmd;
|
int cmd;
|
||||||
|
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
|
@ -2993,18 +2993,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||||
cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */
|
cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case IDM_NEW:
|
case IDM_NEW:
|
||||||
if (!midend_process_key(fe->me, 0, 0, 'n'))
|
if (!midend_process_key(fe->me, 0, 0, UI_NEWGAME))
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
case IDM_RESTART:
|
case IDM_RESTART:
|
||||||
midend_restart_game(fe->me);
|
midend_restart_game(fe->me);
|
||||||
break;
|
break;
|
||||||
case IDM_UNDO:
|
case IDM_UNDO:
|
||||||
if (!midend_process_key(fe->me, 0, 0, 'u'))
|
if (!midend_process_key(fe->me, 0, 0, UI_UNDO))
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
case IDM_REDO:
|
case IDM_REDO:
|
||||||
if (!midend_process_key(fe->me, 0, 0, '\x12'))
|
if (!midend_process_key(fe->me, 0, 0, UI_REDO))
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
case IDM_COPY:
|
case IDM_COPY:
|
||||||
|
|
@ -3026,7 +3026,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IDM_QUIT:
|
case IDM_QUIT:
|
||||||
if (!midend_process_key(fe->me, 0, 0, 'q'))
|
if (!midend_process_key(fe->me, 0, 0, UI_QUIT))
|
||||||
PostQuitMessage(0);
|
PostQuitMessage(0);
|
||||||
break;
|
break;
|
||||||
case IDM_CONFIG:
|
case IDM_CONFIG:
|
||||||
|
|
@ -3405,8 +3405,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case WM_CHAR:
|
case WM_CHAR:
|
||||||
if (!midend_process_key(fe->me, 0, 0, (unsigned char)wParam))
|
{
|
||||||
PostQuitMessage(0);
|
int key = (unsigned char)wParam;
|
||||||
|
if (key == '\x1A') {
|
||||||
|
BYTE keystate[256];
|
||||||
|
if (GetKeyboardState(keystate) &&
|
||||||
|
(keystate[VK_SHIFT] & 0x80) &&
|
||||||
|
(keystate[VK_CONTROL] & 0x80))
|
||||||
|
key = UI_REDO;
|
||||||
|
}
|
||||||
|
if (!midend_process_key(fe->me, 0, 0, key))
|
||||||
|
PostQuitMessage(0);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
if (fe->timer) {
|
if (fe->timer) {
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ has 'descfile' => (required => 1);
|
||||||
% # (individual files or shortcuts or additions to PATH) that are
|
% # (individual files or shortcuts or additions to PATH) that are
|
||||||
% # installed.
|
% # installed.
|
||||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||||
<Directory Id="ProgramFilesFolder" Name="PFiles">
|
<Directory Id="ProgramFiles64Folder" Name="PFiles">
|
||||||
<Directory Id="INSTALLDIR" Name="Simon Tatham's Portable Puzzle Collection">
|
<Directory Id="INSTALLDIR" Name="Simon Tatham's Portable Puzzle Collection">
|
||||||
|
|
||||||
% # The following components all install things in the main
|
% # The following components all install things in the main
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue