This is a larger clean-up of the refresh situation.
The general shift is that refreshes are now mainly triggered by
the (top-level) widgets when they get shown or closed via UIManager.
All refreshes for the widgets when they are in use were handled by
themselves before. This adds the case of showing/closing.
It is the desired result of not having UIManager:show()/:close()
do (full screen) refreshes on its own.
This eliminates the API difference between the extra parameters of
UIManager:show() and setDirty(). They work the same now.
Note that this also eliminates the automatic refresh that took place
before when using show() without refresh options. It always refreshed
the full screen, which led to too big refresh regions all over the
place. Thus, refresh has now explicitly to be asked for, hopefully
encouraging to implement it in the widget that gets shown (and is
aware about the screen region it covers).
Also add an event that is triggered when a widget is closed:
CloseWidget. So a widget can implement "onCloseWidget()" to trigger
actions upon closing - most commonly, this is a refresh for the area
previously taken by the widget. That way, the widget's user does not
have to take measures to ensure that the area is refreshed later.
for now, we have show() automatically call setDirty() for the new
widget, as before. However, now show() takes two arguments for
refresh configuration that will get passed on to setDirty().
For compatibility, the default is here in show() to do a partial
refresh. So if you want no refresh triggered (via this show() call),
add a function that doesn't return anything.
it was set to a full refresh. However, we want to behave as if in
non-scrolling mode and issue a partial refresh. That might get
updated to a full refresh if the full-refresh counter has reached
the limit - which is configurable.
This serves as a good example for the way refreshes are done:
setDirty("all", function() ... end)
* the "all" will have all widgets on screen repainted.
In this case that is needed because the config pane has
different sizes, covering different parts of underlying
widgets. So they need to be repainted every time.
* the function will return the area to refresh and is evaluated
after painting. In this example, we take the area that is covered
by the config pane before switching it (if present at all), and
hand it to the refresh area function as an upvalue.
When the function is called later after painting, it will
use that saved area and combine it with the area that is covered
then by the widget. That way, parts that are covered no more are
included in the refresh area, too.
See documentation in the code.
In short: There is now one single method, setDirty(), that triggers
repaints and/or refreshes.
All variables in UIManager are gone - at least from an external
perspective. Everything is done through setDirty().
This also allows for easier debugging, since all requests come
in via function calls.
when the image (e.g. a PNG) does contain an alpha channel, that can
be honored by ImageWidget. It doesn't do so by default for compatibility
(arguably, we should change that in the future), it has to be enabled
by setting the "alpha" property to "true" (boolean, not string).
external data (and in bad cases our own) can contain invalid byte
sequences in UTF8 strings. A prominent example are file names.
There was a 1-off bug in calculating the allowed length for multibyte
chars, and the iterator was a bit too greedy when stumbling upon
invalid sequences, returning a single "invalid" char for a sequence
up to the point where it became invalid in calculation. Now, we present
one invalid char for the first byte of that sequence and then check
for a valid char starting with the next byte.