This operation is not so slow that it really needs caching. Also
reducing the delay before showing a directory will have more impact
on the user experience than a slightly faster paint.
The way the caching was implemented was rather problematic. Also I'm
not convinced caching is useful at all. So I removed it. If at some
point we decide that caching is a good idea, it would be best to
re-implement it from scratch, so nothing of value is lost by removing
the existing caching code.
One problem was that the prepare method would check the existence of
a screenshot file for every file in the directory, which adds to the
noticable delay before showing a directory which holds many files.
Another problem is there was no upper limit to the number of
screenshots that would be cached. On directories with many screenshots
the memory use could rise to several hundred megabytes, which can be
problematic on some of the systems we want to support.
Also there was a rather nasty hack present to ensure screenshots were
loaded without an alpha channel.
My main doubt about the usefulness of screenshot caching is that
caching will only speed up the showing of an image from the second
time onwards. In typical use, the average screenshot is displayed at
most once. If the image load time is long enough to annoy the user,
any real solution would have to work also for the first showing.
For example, background (asynchronous) loading could be implemented.
All calls to this method are in GMenu2X::initMenu() and they will only
pass valid indices, so the range check was redundant. Also the return
value was never used.
Added an assert to spot any invalid indices from future code.
There are a few exclusive operations for each type. Also we no longer
need the freeWhenDone flag since the class now determines whether the
surface should be freed or not.
In theory a font could be so large that no full row would fit on the
allotted space; in that case showing a partial row is better than
nothing and will avoid bugs where -1 wraps around on unsigned exprs.
Nebuleon spotted a bug in TextManualDialog where the unsigned value
'pages[page].text.size() - rowsPerPage' could wrap around at 0 for
short chapters. I decided to change a bit more than just fixing the
bug though.
This is the convention that most classes stick to. The likely reason
why Dialog didn't stick to the convention was to be able to provide
a default value for this argument, but that feature wasn't very useful
since every caller already had access to the default surface.
Applications with this flag will not have their stdout/stderr
redirected to a log file when logging is enabled. That is a useful
feature also on platforms where we don't micromanage the console.
Currently the launched application is exec-ed from deep within the menu
code. This means a lot of destructors are never run and as a result
for example file descriptors from the menu remain open in the launched
process.
This is a first step to move the launch invocation from a deep call
stack to the top level.
If a text file ends in a newline, the previous line splitting code
would append an empty line at the end, which looked odd. So now we
explicitly check that a newline is only inserted if more characters
follow.
Setting values are now displayed 10 pixels to the right of setting names, as
passed to MenuSetting::draw.
This commit also contains the following cleanups:
* The height of a row is passed to MenuSetting's draw and touchscreen methods.
* MenuSettingRGBA's magic constant (36) to separate the text for a color's
four components is now a named constant.
* MenuSettingRGBA's color preview squares are now rowHeight - 2 pixels tall,
and have a white border surrounded by a black border to help view the color
it contains in both light and dark themes.
* The rectangle behind the selected setting's name is now drawn by that
setting's drawSelected method.
Setting descriptions and help prompts now appear fully even if they are longer
than the screen allows. Translations do not need to worry about allowed text
being wider than the screen in some fonts anymore.
Instead of reading the file line by line and then concatenating those
lines, just load the entire thing in one go. And pay more attention to
error conditions.
The constructors of those classes now accept a string to be wrapped, instead
of a vector to be modified with split lines inserted into its middle.
Along with this conversion, manuals for applications stored in OPK packages
are now transferred into a string without garbage at the end.
This implementation is based on the implementation in TextDialog::preProcess,
with one major difference: it works on the entire input string, copies it much
less as part of its function, and tries to quickly establish a small search
space for the length of the beginning split of each line.
With most standard fonts and sizes, this means up to 9 computations of metrics
per output line.
Multi-line message boxes had the incorrect height.
I also took the opportunity to make named constants out of magic numbers
making up the various message box dimensions.
This reverts commit 0908aa7bb7.
It turns out there are multi-line text messages in use: Nebuleon found
one in the confirmation message when deleting a section.
In commit 950518f3 I changed the component type of RGBAColor from
16-bit to 8-bit integers. Unfortunately, in C++ 8-bit integers are
identical to characters, so this broke the writing of colors to
output streams.
This affects manuals, About GMenu2X, and the Log Viewer.
Instead of trying to compute the width of the entire string, then backing
off one word at a time, TextDialog::preProcess now performs a binary search
on Font::getTextWidth(string) and backs off to the last fitting space, if
there is one, at the last moment.
In Japanese and Chinese text, words are not usually separated by spaces.
Text in these languages is now wrapped when it would reach the edge of the
screen.
I implemented it as four 1-pixel-wide filled rectangles. While this
is not the fastest way to do it, I doubt this will have a significant
impact on overall performance.
Note that the proper way to clip a rectangle outline is to clip the
outline's four lines individually, not clip the rectangle and then
draw a smaller rectangle outline. This means that an optimized drawing
routine would have to be aware of whether clipping occurs, complicating
the code.