61 Commits

Author SHA1 Message Date
33b5c48429 js: Add a new function whereby C can ask JS for a preferred board size
Currently JS has no opinion.
2022-12-10 18:33:00 +00:00
14eb35da4a js: Set the default colour from the CSS background of the canvas
This allows the HTML/CSS to decide that it would like a different
background colour without the need to recompile.  The default if the CSS
specifies no colour (and hence the canvas is transparent) is the same
grey as before.
2022-12-10 17:58:41 +00:00
02f1d55a02 js: Allow CSS to set the font used by the puzzle
This means that the calculated font properties of the HTML canvas now
control what font is used.  The size is overridden, and for monospaced
text so is the family.

I'd like to be able to also specify the monospaced font, maybe using a
CSS variable, but that looks like being quite a lot of extra complexity.

My experience when testing this was that constructing a valid "font"
string for a canvas context is prone to breakage, but broke in a way
that left the font unchanged, so we always set a simple specification
first before trying to construct one from CSS.
2022-12-10 15:30:49 +00:00
ea223a2350 js: Put the puzzle background colour in a CSS variable
It's sometimes useful to be able to have an HTML element that visually
forms an extension of the puzzle's border.  By putting the puzzle's
colour 0 (which we assume to be its background) into a CSS variable,
such elements can do something like "background-color:
var(--puzzle-background)" to get that effect even if the puzzle uses a
non-default background colour.
2022-12-05 23:25:12 +00:00
b967a3ea86 js: Remove support for creating the status bar in JavaScript
Now we depend on its being in the HTML.
2022-11-28 22:51:15 +00:00
271fb7f47c js: More conventional marking of menu item types
Menu items that open dialogue boxes are now marked with ellipses, while
menu items that lead to submenus have pointing triangles.

The triangles are implemented as SVG files embedded in data: URLs in the
CSS, which is kind of silly but also works really well.  There are
suitable characters in Unicode, but some of my test systems don't have
fonts containing them, so maybe the SVG is better.
2022-11-24 16:24:59 +00:00
77c8b50834 js: Allow status bar to be present in the HTML
I'm generally in favour of putting HTML in HTML rather the constructing
it in JavaScript, and this will allow for simplifying the code
eventually.  This only changes the JavaScript to make sure that's in
people's caches before I change the HTML itself.
2022-11-20 19:10:23 +00:00
a90bb4a4ef js: Better handling of games without presets and/or solve
Games with neither presets nor configuration (which may only be the Null
Game) have been slightly broken since the introduction of hierarchical
preset menus, in that the code to remove the "Type..." menu stopped
being called then.  My switch to using radio buttons in menus then broke
them utterly because it's not possible to set the value of an empty
radio group, causing a crash at startup.

Fix this by detected when there's no preset menu, removing the item from
the menu bar, and setting the variable that's meant to indicate this has
been done.

The solve button problem was more subtle, in that only the <button> was
being hidden and not the <li> containing it, which led to the right border of the menu bar being two pixels thick.  Switch to fully removing
the <li> from the DOM, like we now do with the presets menu, since that
also makes my keyboard handler (in another branch) simpler.
2022-11-13 14:05:55 +00:00
c5a2446fae js: Cancel UI events when the mid end says they've been handled
This means that if a key doesn't do anything in a puzzle, it can operate
the browser instead.
2022-11-08 10:27:19 +00:00
4a37f7cf78 Add a way for midend_process_key() to report whether it handled a keypress
This adds a new bool * argument, which can be NULL if front ends don't
care whether the keypress was handled.  Currently they all do that.

Currently, "undo" and "redo" keys are treated as not handled if there's
no move to undo or redo.  This may be a little too strict.
2022-11-08 10:27:19 +00:00
4fdcc54975 js: Make SoftRight act as CURSOR_SELECT2 as well
This way, the front end can intercept one of SoftLeft and SoftRight as a
menu key and leave the other one for the puzzle.  And while we don't
have a working menu, I can use whichever is more convenient.
2022-11-08 10:27:19 +00:00
ee5b02b0ca js: Map the "SoftLeft" key to CURSOR_SELECT2
This is the left soft key on KaiOS phones.  The centre soft key
already sends "Enter", which eventually becomes CURSOR_SELECT.  The
right soft key I'm planning to use to open the menu.
2022-11-08 10:27:19 +00:00
ad9ee5a524 js: Move much of the handling of device pixel ratios to the mid-end
Now that the mid-end knows how to do it, we can remove some complexity
from the front end.
2022-11-08 10:27:02 +00:00
e45cd43aaa Teach the mid-end about device pixel ratios
The device pixel ratio indicates how many physical pixels there are in
the platonic ideal of a pixel, at least approximately.  In Web browsers,
the device pixel ratio is used to represent "retina" displays with
particularly high pixel densities, and also to reflect user-driven
zooming of the page to different text sizes.

The mid-end uses the device pixel ratio to adjust the tile size at
startup, and can also respond to changes in device pixel ratio by
adjusting the time size later.  This is accomplished through a new
argument to midend_size() which can simply be passed as 1.0 in any front
end that doesn't care about this.
2022-11-08 00:57:36 +00:00
1e8169ea94 js: Take device pixel ratio into account when setting default size
This is a bit of a hack.  When setting the puzzle to its default size,
either at startup or from a right-click on the resize handle, we now
scale the default size from midend_size() by the device pixel ratio,
and then pass that back to midend_size().  This does more or less the
right thing, in that the puzzle now starts up at a size that scales
with the font size.

There are still some slight inconsistencies, where sequences of DPR
changes and puzzle parameter changes can have order-dependent effects
on the size of the puzzle.  Happily these effects are small and fairly
hard to observe.
2022-10-27 22:51:54 +01:00
fa58dd85b7 js: Distinguish manual resizes from device pixel ratio changes
This adds a new callback, rescale_puzzle(), that's called when the
device pixel ratio changes.  This means that resize_puzzle() can safely
set the nominal canvas size, which means that manual resizing of the
puzzle now sticks.

Still missing: paying attention to the device pixel ratio when choosing
the initial (or reset) size.
2022-10-27 22:51:54 +01:00
9783bbfbc0 js: Split setting nominal and actual canvas size
Now zooming in and out repeatedly doesn't cause the canvas to wither
away, but user resizes don't stick any more.  Still more to do.
2022-10-27 22:51:54 +01:00
5fae5ca0db js: Be more subtle about cancelling keydown events
Now we only cancel a keydown event if the C keyboard handler recognises
the key and passes it on to the midend.  This doesn't necessarily mean
that the midend has actually done anything with it, of course.  Still,
this is enough to allow F12 to open the developer tools even when the
input focus is on the puzzle.  It also allows for tabbing out of the
puzzle into the links below it.
2022-10-25 20:38:37 +01:00
43c89dd5e1 js: Add a comment explaining the two halves of the key-matching code 2022-10-25 00:50:47 +01:00
d94d671bf9 js: Handle KeyboardEvent.key == "Spacebar"
This is apparently generated in place of " " by Internet Explorer.
2022-10-25 00:48:58 +01:00
35d382019f js: Recognise KeyboardEvent.key == "Escape" 2022-10-24 23:33:09 +01:00
f5ac13c847 js: Add mapping for UI_REDO based on KeyboardEvent.key 2022-10-24 23:19:56 +01:00
768ef770a3 js: Use KeyboardEvent.key for ASCII keystrokes
This requires passing in KeyboardEvent.location from JavaScript so
that we can detect the numeric keypad properly.  Out of caution we
currently only set MOD_NUM_KEYPAD on numbers, like we always have,
but we have enough information to set it on arrow keys, Enter, "+",
etc.

This finally gets '/' and '\' working in Slant again.
2022-10-24 23:13:33 +01:00
0db5fb525b js: Remove the charCode argument from key()
It hasn't been used in a while.
2022-10-24 22:37:30 +01:00
9698732d65 js: Add modern "key" values for Delete and arrow keys
Firefox has emitted "Delete", "ArrowDown" etc since 2015.
2022-10-24 22:22:33 +01:00
322a439d80 js: Use KeyboardEvent.keyCode and .char only as fallbacks
KeyboardEvent.keyCode is a platform-dependent mess.
KeyboardEvent.char is better-defined, but in my browser it's always
null.  KeyboardEvent.key is the right thing to use when we want to
know the semantics of a key.

This commit just re-organises the big "else if" chain in key() so
that all the tests on "key" come first.  That way at least if key and
keyCode disagree, we'll use the more trustworthy one.
2022-10-24 22:07:12 +01:00
c1059c07fb js: Remove braces from big else-if chain in keyboard handler
If there's ever a case where they're unnecessary noise, it's a long
chain of "else if"s guarding single assignment statements.
2022-10-24 21:57:53 +01:00
47905e9547 Revert "WASM: move save file encoding from JS into C."
Now that save files are (even more) officially ASCII, it's perfectly
safe to pass them to JavaScript as UTF-8 strings.

This means that the form in which save files are shipped from C to
JavaScript is the same is the form in which they're shipped from
JavaScript to C.  That allows for doing new things with them, like
writing them to local storage.

This reverts commit f729f51e475ff98d0caf529f0723ef810b1c88ef.
2022-10-21 00:25:34 +01:00
879a6922b0 js: Update permalinks and undo/redo buttons when loading
Without this, the "Undo" button ends up greyed even though it actually
works.  I'm not sure about whether updating the permalinks is necessary:
maybe we don't need that in new_game() either.
2022-10-15 18:23:15 +01:00
f11e93e3bd js: Update comment on possible future enhancements
Load/save has been in the JavaScript backend for a while, as have
prettier controls.  And JavaScript-capable touchscreens are all around
us, if still poorly supported by Puzzles.
2022-10-13 10:07:05 +01:00
a11a5726b2 Add a missing "const" to js_draw_poly and js_canvas_draw_poly 2022-10-13 00:13:00 +01:00
f729f51e47 WASM: move save file encoding from JS into C.
The previous fix worked OK, but it was conceptually wrong. Puzzles
save files are better regarded as binary, not text: the length fields
are measured in bytes, so translating the file into a different
multibyte character encoding would invalidate them.

So it was wrong to fetch a C byte string containing the exactly right
binary data, then translate it into a Javascript string as if decoding
from UTF-8, then retranslate to a representation of a bytewise
encoding via encodeURIComponent, and then label the result as
application/octet-stream.

This probably wouldn't have caused any problems in practice, because I
don't remember any situation in which my save files use characters
outside printable ASCII (plus newline). But it's not actually
forbidden, so a save file might choose to do that some day, so that
UTF-8 decode/reencode hidden in the JS was a latent bug.

Now the URI-encoding is done on the C side, while we still know
exactly what the binary data ought to look like and can be sure we're
translating it byte for byte into the output encoding for the data:
URI. By the time the JS receives a string pointer from get_save_file,
it's already URI-encoded, which _guarantees_ that it's in ASCII and
won't be messed about with by Emscripten's UTF8ToString.
2021-05-23 08:45:55 +01:00
5f5b284c0b Use C99 bool within source modules.
This is the main bulk of this boolification work, but although it's
making the largest actual change, it should also be the least
disruptive to anyone interacting with this code base downstream of me,
because it doesn't modify any interface between modules: all the
inter-module APIs were updated one by one in the previous commits.
This just cleans up the code within each individual source file to use
bool in place of int where I think that makes things clearer.
2018-11-13 21:48:24 +00:00
a550ea0a47 Replace TRUE/FALSE with C99 true/false throughout.
This commit removes the old #defines of TRUE and FALSE from puzzles.h,
and does a mechanical search-and-replace throughout the code to
replace them with the C99 standard lowercase spellings.
2018-11-13 21:48:24 +00:00
cd6cadbecf Adopt C99 bool in the midend API.
This changes parameters of midend_size and midend_print_puzzle, the
return types of midend_process_key, midend_wants_statusbar,
midend_can_format_as_text_now and midend_can_{undo,redo}, the 'bval'
field in struct config_item, and finally the return type of the
function pointer passed to midend_deserialise and identify_game.

The last of those changes requires a corresponding fix in clients of
midend_deserialise and identify_game, so in this commit I've also
updated all the in-tree front ends to match. I expect downstream front
ends will need to do the same when they merge this change.
2018-11-13 21:46:39 +00:00
3618f6a07f Fix NUL-termination bug in saving from Javascript.
The JS code that retrieves the save-file data from emcc.c doesn't
receive a separate length value, but instead expects the data to be in
the form of a NUL-terminated string. But emcc.c wasn't NUL-terminating
it, so the save data could come out with random cruft on the end.
2018-06-21 18:54:08 +01:00
a58c1b216b Make the code base clean under -Wwrite-strings.
I've also added that warning option and -Werror to the build script,
so that I'll find out if I break this property in future.
2017-10-01 16:35:40 +01:00
3276376d1b Assorted char * -> const char * API changes.
I went through all the char * parameters and return values I could see
in puzzles.h by eye and spotted ones that surely ought to have been
const all along.
2017-10-01 16:35:00 +01:00
b3243d7504 Return error messages as 'const char *', not 'char *'.
They're never dynamically allocated, and are almost always string
literals, so const is more appropriate.
2017-10-01 16:34:41 +01:00
de67801b0f Use a proper union in struct config_item.
This allows me to use different types for the mutable, dynamically
allocated string value in a C_STRING control and the fixed constant
list of option names in a C_CHOICES.
2017-10-01 16:34:41 +01:00
d72db91888 Map Ctrl-Shift-Z to Redo.
This is in addition to the existing keystrokes r, ^R and ^Y. I've
become used to Ctrl-Shift-Z in other GUI games, and my fingers keep
getting confused when my own puzzles don't handle it the same way.
2017-09-20 18:03:44 +01:00
e4d05c36d9 Generate special fake keypresses from menu options.
This fixes an amusing UI bug that I think can currently only come up
in the unpublished puzzle 'Group', but there's no reason why other
puzzles _couldn't_ do the thing that triggers the bug, if they wanted
to.

Group has unusual keyboard handling, in that sometimes (when a cell is
selected for input and the key in question is valid for the current
puzzle size) the game's interpret_move function will eat keystrokes
like 'n' and 'u' that would otherwise trigger special UI events like
New Game or Undo.

The bug is that fake keypress events generated from the GUI menus
looked enough like those keystrokes that interpret_move would eat
those too. So if you start, say, a 16x16 Group puzzle, select an empty
cell, and then choose 'new game' from the menu, Group will enter 'n'
into the cell instead of starting a new game!

I've fixed this by inventing a new set of special keystroke values
called things like UI_NEWGAME and UI_UNDO, and having the GUI menus in
all my front ends generate those in place of 'n' and 'u'. So now the
midend can tell the difference between 'n' on the keyboard and New
Game from the menu, and so Group can treat them differently too. In
fact, out of sheer overcaution, midend.c will spot keystrokes in this
range and not even _pass_ them to the game back end, so Group
shouldn't be able to override these special events even by mistake.

One fiddly consequence is that in gtk.c I've had to rethink the menu
accelerator system. I was adding visible menu accelerators to a few
menu items, so that (for example) 'U' and 'R' showed up to the right
of Undo and Redo in the menu. Of course this had the side effect of
making them real functioning accelerators from GTK's point of view,
which activate the menu item in the same way as usual, causing it to
send whatever keystroke the menu item generates. In other words,
whenever I entered 'n' into a cell in a large Group game, this was the
route followed by even a normal 'n' originated from a real keystroke -
it activated the New Game menu item by mistake, which would then send
'n' by mistake instead of starting a new game!

Those mistakes cancelled each other out, but now I've fixed the
latter, I've had to fix the former too or else the GTK front end would
now undo all of this good work, by _always_ translating 'n' on the
keyboard to UI_NEWGAME, even if the puzzle would have wanted to treat
a real press of 'n' differently. So I've fixed _that_ in turn by
putting those menu accelerators in a GtkAccelGroup that is never
actually enabled on the main window, so the accelerator keys will be
displayed in the menu but not processed by GTK's keyboard handling.

(Also, while I was redoing this code, I've removed the logic in
add_menu_item_with_key that reverse-engineered an ASCII value into
Control and Shift modifiers plus a base key, because the only
arguments to that function were fixed at compile time anyway so it's
easier to just write the results of that conversion directly into the
call sites; and I've added the GTK_ACCEL_LOCKED flag, in recognition
of the fact that _because_ these accelerators are processed by a weird
mechanism, they cannot be dynamically reconfigured by users and
actually work afterwards.)
2017-09-20 18:01:52 +01:00
721119e4a6 Support for loading games in Javascript puzzles.
This is done by showing a dialog containing an <input type="file">
through which the user can 'upload' a save file - though, of course,
the 'upload' doesn't go to any HTTP server, but only into the mind of
the Javascript running in the same browser.

It would be even nicer to support drag-and-drop as an alternative UI
for getting the save file into the browser, but that isn't critical to
getting the first version of this feature out of the door.
2017-09-05 20:58:05 +01:00
1bf591a573 Support for saving games in Javascript puzzles.
This is done by getting midend_serialise to produce the complete
saved-game file as an in-memory string buffer, and then encoding that
into a data: URI which we provide to the user as a hyperlink in a
dialog box. The hyperlink has the 'download' attribute, which means
clicking on it should automatically offer to save the file, and also
lets me specify a not-too-silly default file name.
2017-09-05 20:56:55 +01:00
a7dc17c425 Rework the preset menu system to permit submenus.
To do this, I've completely replaced the API between mid-end and front
end, so any downstream front end maintainers will have to do some
rewriting of their own (sorry). I've done the necessary work in all
five of the front ends I keep in-tree here - Windows, GTK, OS X,
Javascript/Emscripten, and Java/NestedVM - and I've done it in various
different styles (as each front end found most convenient), so that
should provide a variety of sample code to show downstreams how, if
they should need it.

I've left in the old puzzle back-end API function to return a flat
list of presets, so for the moment, all the puzzle backends are
unchanged apart from an extra null pointer appearing in their
top-level game structure. In a future commit I'll actually use the new
feature in a puzzle; perhaps in the further future it might make sense
to migrate all the puzzles to the new API and stop providing back ends
with two alternative ways of doing things, but this seemed like enough
upheaval for one day.
2017-04-26 21:51:23 +01:00
bc2c1f69fd Javascript puzzles: switch to a CSS-based drop-down system.
The previous control buttons and dropdowns based on form elements were
always a bit ugly: partly in a purely visual sense, and partly because
of the nasty bodge I had to do with splitting the usual 'Custom' game
type menu item into two (to get round the fact that if an element of a
<select> is already selected, browsers won't send an event when it's
re-selected). Also, I'm about to want to introduce hierarchical
submenus in the Type menu, and <select> doesn't support that at all.

So here's a replacement system which does everything by CSS
properties, including the popping-up of menus when the mouse moves
over their parent menu item. (Thanks to the Internet in general for
showing me how that trick is done.)
2017-04-26 21:48:11 +01:00
d31eff1483 Handle the space bar in the Javascript front end.
I wasn't passing it through at all, causing CURSOR_SELECT2 dependent
keyboard UI not to be reachable.
2015-01-13 19:19:05 +00:00
5b367167af Fix two compile warnings in emcc.c.
Reported by a user, who didn't say what version of Emscripten they
were using but it must not be the same as mine.
2014-11-30 17:00:45 +00:00
5e637af243 Add a missing #include.
[originally from svn r10179]
2014-04-20 08:47:25 +00:00
c0fff857fd Add a draggable resize handle to the JS puzzles.
Rather than design an ersatz 'window frame' surrounding the puzzle
canvas, I've simply overlaid the resize handle on the corner of the
puzzle itself (canvas or status bar, depending on whether the latter
exists), trusting that all games in my collection provide a reasonable
border within their drawing area. (OS X already does this with its
resize handle, so it's not as if there's no precedent.)

Unlike the desktop versions, I control the resize behaviour completely
in this environment, so I can constrain the canvas to only ever be
sensible sizes with no dead space round the edges (and, in particular,
preserve the aspect ratio).

Right-clicking the resize handle will restore the puzzle's default
tile size. I had intended to implement a maximise-to-browser-window
button too, but was annoyingly foiled by scrollbars - if you maximise
to the current window width, and as a result the text below the puzzle
scrolls off the bottom, then a vertical scrollbar appears and eats
into the width you just maximised to. Gah.

[originally from svn r9822]
2013-04-07 10:24:37 +00:00