Until now, every (even the tiniest) widget's change of the enabled state
resulted in a redraw of a complete *dialog*. Why this was needed and how
it has been fixed requires a bit of explanation.
There are two buffers to render the widgets in: Backbuffer and Screen
(selected by ThemeEngine::drawToBackbuffer() and
ThemeEngine::drawToScreen() respectively, setting
VectorRenderer::_activeSurface). Then there are two layers/flags:
kDrawLayerBackground and kDrawLayerForeground
(selected in Dialog::drawDialog(), setting ThemeEngine::_layerToDraw).
When asked for a complete dialog rebuild in GuiManager::redraw()
(kRedrawCloseDialog, kRedrawFull) the widgets of every dialog,
regardless of their layer, are drawn into Backbuffer and then copied
into Screen.
When asked for a partial dialog rebuild (kRedrawOpenDialog,
kRedrawTopDialog) the widgets of the topmost dialog marked with
kDrawLayerBackground are drawn into Backbuffer, then copied into Screen
and finally the widgets marked with kDrawLayerForeground are drawn into
Screen *only*.
When redraw() is called just within the GuiManager's event loop the
widgets of the topmost dialog are drawn into Screen *only*. And this is
where the layers become important.
When rebuilding the dialog, it doesn't really matter which layer has
been defined for a widget: Backbuffer contains the ones with
kDrawLayerBackground and Screen will supply the rest with
kDrawLayerForeground, if needed. But which layer is taken into account
when calling Dialog::drawWidgets() ?
It is important to realize that the content of Backbuffer is
defined by the widget's initial state (idle or disabled): so Backbuffer
will contain either "idle color" or "disabled color" after dialog's
creation.
ThemeEngine::drawDD() does two checks:
1. if widget has kDrawLayerBackground set *and* _activeSurface is
Screen, copy the widget from Backbuffer to Screen
2. if widget's layer is the same as _layerToDraw, draw the widget into
_activeSurface
This is what happens in redraw(kRedrawDisabled) for kDrawLayerBackground
widgets:
- Backbuffer contains an idle/disabled (depending on its initial state)
rendition of the widget
- widget is copied from Backbuffer to Screen (1st check in drawDD())
- widget is not drawn into Screen as _layerToDraw is
kDrawLayerForeground (2nd check in drawDD())
Summary: when switching between idle/disabled state, widget's color is
not updated.
This is what happens in redraw(kRedrawDisabled) for kDrawLayerForeground
widgets:
- Backbuffer contains an idle/disabled (depending on its initial state)
rendition of the widget
- widget is not copied from Backbuffer to Screen as widget has
kDrawLayerForeground set (1st check in drawDD())
- widget is drawn into Screen as _layerToDraw is still
kDrawLayerForeground from the last redraw() (2nd check in drawDD())
Summary: when switching between idle/disabled state, widget's color is
correctly updated and not restored from Backbuffer.
Initially, I set up "button idle" to be rendered in the foreground
layer, same as "button disabled". However @lephilousophe suggested a
great improvement: render "button idle" still in the background but make
"button disabled" its child (in the foreground). Worked like a charm as
it just mimics the hovering behaviour.
And this is why hovering doesn't require scheduleTopDialogRedraw():
- Backbuffer contains an idle [kDrawLayerBackground] rendition of the
widget
- when highlighted [kDrawLayerForeground], widget is not copied from
Backbuffer to Screen
- widget is drawn into Screen
Unhovering:
- Backbuffer contains an idle [kDrawLayerBackground] rendition of the
widget
- when idle [kDrawLayerBackground], widget is copied from Backbuffer to
Screen
- widget is not drawn into Screen
The resize() function has the option to do the scaling, but
adding it to the construtor avoids having to then call resize().
Also this makes more explicit that by default the sizes are not
scaled. The reason for not scaling by default is because values
with get from the ThemeEngine are already scaled.
Clicking on a checkbox (and, presumably, a radio button) would leave it
in the "pressed" state, which would inhibit tooltips for it. Now the
unpressed state is cleared along with _duringPress for both these
classes. There are other widgets that inherit from ButtonWidget, but
they either already did this, or didn't override handleMouseUp(), so
they should be fine.
Removes interfering invisible thumbnail with list item selection in saveload-dialog (OpenGL, large scale)
I'm issuing this as a PR because I'm unsure if this fix is ok, since it affects all GraphicsWidget objects, not just the one for thumbnail in saveload-dialog. Also not sure if some similar check should be done in the other setGfx() methods in widget.cpp to prevent similar issues.
Note that an alternative fix, which also works, would be to only modify gui/saveload-dialog.cpp and method SaveLoadChooserSimple::updateSelection(), to check for _gfxWidget isVisible status before calling: _gfxWidget->setGfx(thumb, true);