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.
I want to remove the dependency on SDL_gfx, since only two functions
from that library are actually used. Also this new blend implementation
is more optimized, especially the 32bpp case, which is the one most
platforms are using.
This is the opposite of the old situation, when the structs were
unraveled.
The definitions for the alternative styles were moved to the header,
so the compiler has more opportunities for optimizing the conversions.
This allows for faster scrolling between section links, in file and directory
selectors, and in manuals, without repeatedly pressing buttons.
The setting's unit is repetitions per second. Its default value is set to
10, and anything between 0 (disabled) and 20 (50 ms) is acceptable.
Grabbing &(instance of GMenu2X).confInt["buttonRepeatRate"] is unsafe, because
the storage for the slot may move as the slot is deleted or added. Instead, a
callback jumps back into the context of an InputManager so the value can be
read from a GMenu2X object's configuration.
A GMenu2X object is also passed to InputManager::init.
Previously, one would check the value in &confInt["someKey"] by passing a
reference to it to evalIntConf. However, because this passing of the reference
went through std::unordered_map::operator[], it created a slot with the named
key and initialised its value with the default constructor of int, which
placed 0 there, if it didn't exist. If the value of 0 was acceptable for the
setting, then 0 as the value selected by the user was indistinguishable from
a slot that had been just created and had to be set to its default.
Now, the std::unordered_map is passed along with the key so that evalIntConf
can check whether the key exists and, if it doesn't exist, set the value to
its default.
Include utilities.h in gmenu2x.h instead of the reverse. One type definition
used by utilities.cpp is moved there (ConfIntHash) and for consistency
ConfStrHash is moved there as well.
When trying to test the previous commit, I couldn't find any place in
the application where strings containing newlines are drawn. So I'm
assuming this is an unnecessary feature, until someone comes up with
a test case proving otherwise.
Yeah, I'm too lazy to review all the code that draws text...