When there's no drag in progress, cancelling the drag has no effect.
Returning NULL lets the front-end know this, which in particular means
the Backspace key can leave the app in KaiOS.
Older Firefox versions don't support "-moz-appearance: none" on radio
buttons, which seems to mean that the specifies padding for them
doesn't appear. Using a space character instead works fine, so do that
everywhere. This seems to move the text slightly closer to the tick on
browsers that do support "appearance: none", but the result is quite
acceptable.
This also makes the focus outline on the ticks slightly less weird.
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.
The C code in the Emscripten front-end already keeps a timer_active
variable to ensure that the timer can be activated only when it's
inactive, and deactivated only when it's active. Adjusting the
JavaScript side to rely on this makes the code much simpler. The only
oddity is that it now requests a new animation frame before calling the
callback so that it's ready to be cancelled if the callback decides to
deactivate the timer.
I think this has been broken since a752e73, when the canvas changed to
being hidden, and hence unable to receive keyboard focus, when the page
loaded. I've now moved the focus() call to after the canvas gets
displayed.
This is the wrong attribute, and the correct type="text/css" is
deprecated by MDN. Since it's never worked, the deprecated attribute
presumably isn't needed either.
They can now be specified by sticking some JSON in a <script> element in
the Web page:
<script id="environment" type="application/json">
{ "LOOPY_DEFAULT": "20x10t11dh" }
</script>
This isn't brilliantly useful, but it does allow for changing settings
without recompiling.
Now that we're using flex layout, whitespace in the menu isn't scary and
we can use it to make the HTML readable.
Also finally remove the "afterseparator" class that's long obsolete.
You can always use ".separator + *" as a selector instead.
Presets are now radio buttons with labels, and menu items that take
actions are now buttons. The <li> representing each menu item is now a
thin wrapper around another element: a <label> for radio buttons, a
<button> for other buttons, and a <div> for submenu headings. All of
the things that previously applied to the <li> now apply to that inner
element instead.
This means that presets can now use the standard "checked" attribute to
indicate which one is selected, and buttons can be disabled using the
standard "disabled" attribute. It also means that we can query and set
the state of all the presets at once through their RadioNodeList.
I think this should also make the menus more accessible, and make it
easier to make them keyboard-controllable.
... and then decide there was no excuse for renaming the variable, so
now it has the same name it had before I started using
Window.requestAnimationFrame().
This is an API specifically designed for the purposes of timing
animations. Unlike setInterval, it tries to synchronise with the screen
refresh rate. It naturally passes us timing information, saving the
need to construct a Date object every frame. It has the nice feature
that browsers (at least Firefox 91) will call it less frequently when
the puzzle page isn't visible, which saves CPU time in puzzles that run
a timer continuously.
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.
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.
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.
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.
With very small tile sizes, js_canvas_find_font_midpoint() can throw an
exception. When it was called from update_pixel_ratio(), this prevented
the new MediaQueryList from being created, which meant that the puzzle
stopped noticing changes of device pixel ratio.
Now update_pixel_ratio() establishes a new MediaQueryList before calling
rescale_puzzle(), so the exception can't break it. Catching the
exception properly would be even better, of course.
It would have helped in the previous commit if I'd tried actually
_playing_ the game, not just admiring it in its initial state. When I
did, I found that lines weren't being fully overdrawn, which turned
out to be because the clip rectangle was being set too narrow.
This is now important due to Ben's changes in the web frontend. On
high-DPI displays, the canvas is the same overall size as before, but
it's scaled up by increasing the game's tilesize rather than the
browser scaling the image after the game redraws.
Loopy ought to have been scaling its line thicknesses all along, but
forgot. Easily fixed.
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.
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.
This has the entertaining consequence that repeatedly zooming in and out
causes puzzles to gradually shrink, thus demonstrating that recording
the nominal size correctly will be necessary.
Despite my stylistic downgrades, it still used two features not present
in Firefox 48, and hence KaiOS 2.5: passing options to addEventListener,
and calling addEventListener on a MediaQueryList at all. Now it uses
the older addListener method and explicitly removes each listener as
soon as it's called.
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.
At least in modern browsers (and I suspect in all browsers), cancelling
a keydown event ensures that the subsequent keypress event doesn't fire.
See <https://w3c.github.io/uievents/#keys-cancelable-keys>.
So there's no point in having a handler on keypress events that just
tries to cancel them as well. Removing the handler doesn't do much now,
but it opens the possibility of being a bit more selective about which
keydown events we cancel.
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.