diff options
author | Bastien Bouclet | 2019-12-28 10:43:58 +0100 |
---|---|---|
committer | Bastien Bouclet | 2020-01-04 10:56:25 +0100 |
commit | c0d8b6d9fc73abc8de4575686e0776e3468d37b2 (patch) | |
tree | 156e4305363210c7a52a2d90985d71e1cd22a4ce /gui/ThemeLayout.cpp | |
parent | 303ee2694f4e85d3d9796068e33d2d48ca100e8a (diff) | |
download | scummvm-rg350-c0d8b6d9fc73abc8de4575686e0776e3468d37b2.tar.gz scummvm-rg350-c0d8b6d9fc73abc8de4575686e0776e3468d37b2.tar.bz2 scummvm-rg350-c0d8b6d9fc73abc8de4575686e0776e3468d37b2.zip |
GUI: Introduce dynamic layouts
Prior to this change, a GUI layout was only affected by the screen size.
Now, a layout can additionally be influenced by the GUI dialog and widgets
that uses it. This capability is leveraged to implement the following
features:
* Layout elements that are not bound to a GUI widget do not take space.
This means that dialogs where the widgets shown depend on for example
a feature being enabled at configure time no longer have blank spaces.
* Widgets can define a minimal required size for their contents not to be
cut. For now this is only used for buttons so their width is always
sufficient for their caption not to be cut. This mechanism could be
applied to other widget types in the future.
Diffstat (limited to 'gui/ThemeLayout.cpp')
-rw-r--r-- | gui/ThemeLayout.cpp | 100 |
1 files changed, 91 insertions, 9 deletions
diff --git a/gui/ThemeLayout.cpp b/gui/ThemeLayout.cpp index a05ac8797e..eeaaf1e465 100644 --- a/gui/ThemeLayout.cpp +++ b/gui/ThemeLayout.cpp @@ -23,6 +23,9 @@ #include "common/util.h" #include "common/system.h" +#include "gui/gui-manager.h" +#include "gui/widget.h" +#include "gui/ThemeEval.h" #include "gui/ThemeLayout.h" #include "graphics/font.h" @@ -49,6 +52,16 @@ void ThemeLayout::importLayout(ThemeLayout *layout) { } } +void ThemeLayout::resetLayout() { + _x = 0; + _y = 0; + _w = _defaultW; + _h = _defaultH; + + for (uint i = 0; i < _children.size(); ++i) + _children[i]->resetLayout(); +} + bool ThemeLayout::getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) { if (name.empty()) { assert(getLayoutType() == kLayoutMain); @@ -154,14 +167,73 @@ Graphics::TextAlign ThemeLayoutWidget::getWidgetTextHAlign(const Common::String return Graphics::kTextAlignInvalid; } -void ThemeLayoutMain::reflowLayout() { +void ThemeLayoutWidget::reflowLayout(Widget *widgetChain) { + Widget *guiWidget = getWidget(widgetChain); + if (!guiWidget) { + return; + } + + int minWidth = -1; + int minHeight = -1; + guiWidget->getMinSize(minWidth, minHeight); + + if (_w != -1 && minWidth != -1 && minWidth > _w) { + _w = minWidth; + } + + if (_h != -1 && minHeight != -1 && minHeight > _h) { + _h = minHeight; + } +} + +bool ThemeLayoutWidget::isBound(Widget *widgetChain) const { + Widget *guiWidget = getWidget(widgetChain); + return guiWidget != nullptr; +} + +Widget *ThemeLayoutWidget::getWidget(Widget *widgetChain) const { + const ThemeLayout *topLevelLayout = this; + while (topLevelLayout->_parent) { + topLevelLayout = topLevelLayout->_parent; + } + + assert(topLevelLayout && topLevelLayout->getLayoutType() == kLayoutMain); + const ThemeLayoutMain *dialogLayout = static_cast<const ThemeLayoutMain *>(topLevelLayout); + + Common::String widgetName = Common::String::format("%s.%s", dialogLayout->getName(), _name.c_str()); + return Widget::findWidgetInChain(widgetChain, widgetName.c_str()); +} + +void ThemeLayoutMain::reflowLayout(Widget *widgetChain) { assert(_children.size() <= 1); + resetLayout(); + + if (_overlays == "screen") { + _x = 0; + _y = 0; + _w = g_system->getOverlayWidth(); + _h = g_system->getOverlayHeight(); + } else if (_overlays == "screen_center") { + _x = -1; + _y = -1; + _w = -1; + _h = -1; + } else { + if (!g_gui.xmlEval()->getWidgetData(_overlays, _x, _y, (uint16 &) _w, (uint16 &) _h)) { + warning("Unable to retrieve overlayed dialog position %s", _overlays.c_str()); + } + } + + if (_x >= 0) _x += _inset; + if (_y >= 0) _y += _inset; + if (_w >= 0) _w -= 2 * _inset; + if (_h >= 0) _h -= 2 * _inset; + if (_children.size()) { - _children[0]->resetLayout(); _children[0]->setWidth(_w); _children[0]->setHeight(_h); - _children[0]->reflowLayout(); + _children[0]->reflowLayout(widgetChain); if (_w == -1) _w = _children[0]->getWidth(); @@ -177,7 +249,7 @@ void ThemeLayoutMain::reflowLayout() { } } -void ThemeLayoutStacked::reflowLayoutVertical() { +void ThemeLayoutStacked::reflowLayoutVertical(Widget *widgetChain) { int curX, curY; int resize[8]; int rescount = 0; @@ -188,9 +260,9 @@ void ThemeLayoutStacked::reflowLayoutVertical() { _h = _padding.top + _padding.bottom; for (uint i = 0; i < _children.size(); ++i) { + if (!_children[i]->isBound(widgetChain)) continue; - _children[i]->resetLayout(); - _children[i]->reflowLayout(); + _children[i]->reflowLayout(widgetChain); if (_children[i]->getWidth() == -1) _children[i]->setWidth((_w == -1 ? getParentWidth() : _w) - _padding.left - _padding.right); @@ -225,6 +297,11 @@ void ThemeLayoutStacked::reflowLayoutVertical() { if (!_children.empty()) _h -= _spacing; + // If the width is not set at this point, then we have no bound widgets. + if (!fixedWidth && _w == -1) { + _w = 0; + } + // If there were any items with undetermined height, then compute and set // their height now. We do so by determining how much space is left, and // then distributing this equally over all items which need auto-resizing. @@ -243,7 +320,7 @@ void ThemeLayoutStacked::reflowLayoutVertical() { } } -void ThemeLayoutStacked::reflowLayoutHorizontal() { +void ThemeLayoutStacked::reflowLayoutHorizontal(Widget *widgetChain) { int curX, curY; int resize[8]; int rescount = 0; @@ -254,9 +331,9 @@ void ThemeLayoutStacked::reflowLayoutHorizontal() { _w = _padding.left + _padding.right; for (uint i = 0; i < _children.size(); ++i) { + if (!_children[i]->isBound(widgetChain)) continue; - _children[i]->resetLayout(); - _children[i]->reflowLayout(); + _children[i]->reflowLayout(widgetChain); if (_children[i]->getHeight() == -1) _children[i]->setHeight((_h == -1 ? getParentHeight() : _h) - _padding.top - _padding.bottom); @@ -291,6 +368,11 @@ void ThemeLayoutStacked::reflowLayoutHorizontal() { if (!_children.empty()) _w -= _spacing; + // If the height is not set at this point, then we have no bound widgets. + if (!fixedHeight && _h == -1) { + _h = 0; + } + // If there were any items with undetermined width, then compute and set // their width now. We do so by determining how much space is left, and // then distributing this equally over all items which need auto-resizing. |