GUI: tabs with scrollbars
This commit is contained in:
parent
552ea788ce
commit
30a8d927a1
15 changed files with 53 additions and 35 deletions
|
@ -377,7 +377,7 @@ void ConfigDialog::apply() {
|
|||
}
|
||||
|
||||
ExtraGuiOptionsWidget::ExtraGuiOptionsWidget(GuiObject *containerBoss, const Common::String &name, const Common::String &domain, const ExtraGuiOptions &options) :
|
||||
OptionsContainerWidget(containerBoss, name, dialogLayout(domain), true, domain),
|
||||
OptionsContainerWidget(containerBoss, name, dialogLayout(domain), false, domain),
|
||||
_options(options) {
|
||||
|
||||
for (uint i = 0; i < _options.size(); i++) {
|
||||
|
|
|
@ -183,25 +183,21 @@ EditGameDialog::EditGameDialog(const Common::String &domain)
|
|||
}
|
||||
|
||||
//
|
||||
// 2) The engine tab (shown only if the engine implements one or there are custom engine options)
|
||||
// 2) The engine's game settings (shown only if the engine implements one or there are custom engine options)
|
||||
//
|
||||
|
||||
if (metaEnginePlugin) {
|
||||
int tabId = tab->addTab(_("Engine"), "GameOptions_Engine");
|
||||
|
||||
const MetaEngineDetection &metaEngineDetection = metaEnginePlugin->get<MetaEngineDetection>();
|
||||
metaEngineDetection.registerDefaultSettings(_domain);
|
||||
if (enginePlugin) {
|
||||
enginePlugin->get<MetaEngine>().registerDefaultSettings(_domain);
|
||||
_engineOptions = enginePlugin->get<MetaEngine>().buildEngineOptionsWidgetDynamic(tab, "GameOptions_Engine.Container", _domain);
|
||||
_engineOptions = enginePlugin->get<MetaEngine>().buildEngineOptionsWidgetDynamic(tab, "GameOptions_Game.Container", _domain);
|
||||
}
|
||||
if (!_engineOptions)
|
||||
_engineOptions = metaEngineDetection.buildEngineOptionsWidgetStatic(tab, "GameOptions_Engine.Container", _domain);
|
||||
_engineOptions = metaEngineDetection.buildEngineOptionsWidgetStatic(tab, "GameOptions_Game.Container", _domain);
|
||||
|
||||
if (_engineOptions) {
|
||||
_engineOptions->setParentDialog(this);
|
||||
} else {
|
||||
tab->removeTab(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,12 @@ void GuiObject::resize(int x, int y, int w, int h, bool scale) {
|
|||
}
|
||||
}
|
||||
|
||||
Widget *GuiObject::addChild(Widget *newChild) {
|
||||
Widget *oldFirstWidget = _firstWidget;
|
||||
_firstWidget = newChild;
|
||||
return oldFirstWidget;
|
||||
}
|
||||
|
||||
void GuiObject::reflowLayout() {
|
||||
if (!_name.empty()) {
|
||||
int16 w, h;
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
virtual void setTextDrawableArea(const Common::Rect &r) { _textDrawableArea = r; }
|
||||
|
||||
virtual void resize(int x, int y, int w, int h, bool scale = true);
|
||||
virtual Widget *addChild(Widget *newChild);
|
||||
|
||||
virtual int16 getRelX() const { return _x; }
|
||||
virtual int16 getRelY() const { return _y; }
|
||||
|
|
|
@ -1328,6 +1328,7 @@
|
|||
type = 'PopUp'
|
||||
/>
|
||||
</layout>
|
||||
<widget name = 'Container'/>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
|
@ -1368,12 +1369,6 @@
|
|||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GameOptions_Engine' overlays = 'Dialog.GameOptions.TabWidget'>
|
||||
<layout type = 'vertical' padding = '0, 0, 0, 0'>
|
||||
<widget name = 'Container'/>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
|
||||
<layout type = 'vertical' padding = '16, 16, 16, 16' align = 'center'>
|
||||
<widget name = 'Logo'
|
||||
|
|
|
@ -1307,6 +1307,7 @@
|
|||
type = 'PopUp'
|
||||
/>
|
||||
</layout>
|
||||
<widget name = 'Container'/>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
|
@ -1347,12 +1348,6 @@
|
|||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GameOptions_Engine' overlays = 'Dialog.GameOptions.TabWidget'>
|
||||
<layout type = 'vertical' padding = '0, 0, 0, 0'>
|
||||
<widget name = 'Container'/>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
|
||||
<layout type = 'vertical' padding = '4, 4, 4, 4' align = 'center' spacing='2'>
|
||||
<widget name = 'Title'
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -50,9 +50,7 @@ Widget::Widget(GuiObject *boss, const Common::String &name, const Common::U32Str
|
|||
}
|
||||
|
||||
void Widget::init() {
|
||||
// Insert into the widget list of the boss
|
||||
_next = _boss->_firstWidget;
|
||||
_boss->_firstWidget = this;
|
||||
_next = _boss->addChild(this);
|
||||
_needsRedraw = true;
|
||||
}
|
||||
|
||||
|
@ -1045,10 +1043,15 @@ void OptionsContainerWidget::reflowLayout() {
|
|||
}
|
||||
|
||||
Widget *w = _firstWidget;
|
||||
int16 minY = getAbsY();
|
||||
int maxY = minY;
|
||||
while (w) {
|
||||
w->reflowLayout();
|
||||
minY = MIN(minY, w->getAbsY());
|
||||
maxY = MAX(maxY, w->getAbsY() + w->getHeight());
|
||||
w = w->next();
|
||||
}
|
||||
_h = maxY - minY;
|
||||
}
|
||||
|
||||
bool OptionsContainerWidget::containsWidget(Widget *widget) const {
|
||||
|
|
|
@ -121,6 +121,7 @@ public:
|
|||
void init();
|
||||
|
||||
void setNext(Widget *w) { _next = w; }
|
||||
void setBoss(GuiObject *newBoss) { _boss = newBoss; }
|
||||
Widget *next() { return _next; }
|
||||
|
||||
int16 getAbsX() const override { return _x + _boss->getChildX(); }
|
||||
|
|
|
@ -59,7 +59,6 @@ void ScrollContainerWidget::recalc() {
|
|||
|
||||
//calculate virtual height
|
||||
const int spacing = g_gui.xmlEval()->getVar("Global.Font.Height", 16); //on the bottom
|
||||
int h = 0;
|
||||
int min = spacing, max = 0;
|
||||
Widget *ptr = _firstWidget;
|
||||
while (ptr) {
|
||||
|
@ -70,7 +69,7 @@ void ScrollContainerWidget::recalc() {
|
|||
}
|
||||
ptr = ptr->next();
|
||||
}
|
||||
h = max - min;
|
||||
int h = max - min;
|
||||
|
||||
if (h <= _limitH) _scrolledY = 0;
|
||||
if (_scrolledY > h - _limitH) _scrolledY = 0;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "common/util.h"
|
||||
#include "gui/widgets/tab.h"
|
||||
#include "gui/gui-manager.h"
|
||||
#include "gui/widgets/scrollcontainer.h"
|
||||
|
||||
#include "gui/ThemeEval.h"
|
||||
|
||||
|
@ -90,12 +91,10 @@ TabWidget::~TabWidget() {
|
|||
// having been switched using setActiveTab() afterward, then the
|
||||
// firstWidget in the _tabs list for the active tab may not be up to
|
||||
// date. So update it now.
|
||||
if (_activeTab != -1)
|
||||
_tabs[_activeTab].firstWidget = _firstWidget;
|
||||
_firstWidget = nullptr;
|
||||
for (uint i = 0; i < _tabs.size(); ++i) {
|
||||
delete _tabs[i].firstWidget;
|
||||
_tabs[i].firstWidget = nullptr;
|
||||
delete _tabs[i].scrollWidget;
|
||||
_tabs[i].scrollWidget = nullptr;
|
||||
}
|
||||
_tabs.clear();
|
||||
delete _navRight;
|
||||
|
@ -121,6 +120,7 @@ int TabWidget::addTab(const Common::U32String &title, const Common::String &dial
|
|||
newTab.title = title;
|
||||
newTab.dialogName = dialogName;
|
||||
newTab.firstWidget = nullptr;
|
||||
newTab.scrollWidget = nullptr;
|
||||
|
||||
// Determine the new tab width
|
||||
int newWidth = g_gui.getStringWidth(title) + _titleSpacing;
|
||||
|
@ -132,24 +132,34 @@ int TabWidget::addTab(const Common::U32String &title, const Common::String &dial
|
|||
|
||||
int numTabs = _tabs.size();
|
||||
|
||||
// Activate the new tab
|
||||
// Activate the new tab, also writes back our _firstWidget
|
||||
setActiveTab(numTabs - 1);
|
||||
|
||||
_tabs.back().scrollWidget = new ScrollContainerWidget(this, "", dialogName);
|
||||
|
||||
return _activeTab;
|
||||
}
|
||||
|
||||
Widget *TabWidget::addChild(Widget *newChild) {
|
||||
if (_activeTab == -1 || _tabs[_activeTab].scrollWidget == nullptr)
|
||||
return Widget::addChild(newChild);
|
||||
|
||||
newChild->setBoss(_tabs[_activeTab].scrollWidget);
|
||||
_firstWidget = newChild;
|
||||
return _tabs[_activeTab].scrollWidget->addChild(newChild);
|
||||
}
|
||||
|
||||
void TabWidget::removeTab(int tabID) {
|
||||
assert(0 <= tabID && tabID < (int)_tabs.size());
|
||||
|
||||
// Deactivate the tab if it's currently the active one
|
||||
if (tabID == _activeTab) {
|
||||
_tabs[tabID].firstWidget = _firstWidget;
|
||||
releaseFocus();
|
||||
_firstWidget = nullptr;
|
||||
}
|
||||
|
||||
// Dispose the widgets in that tab and then the tab itself
|
||||
delete _tabs[tabID].firstWidget;
|
||||
delete _tabs[tabID].scrollWidget;
|
||||
_tabs.remove_at(tabID);
|
||||
|
||||
// Adjust _firstVisibleTab if necessary
|
||||
|
@ -333,11 +343,13 @@ void TabWidget::reflowLayout() {
|
|||
_tabs[_activeTab].firstWidget = _firstWidget;
|
||||
|
||||
for (uint i = 0; i < _tabs.size(); ++i) {
|
||||
_tabs[i].scrollWidget->setPos(_x, _y);
|
||||
_tabs[i].scrollWidget->setSize(_w, _h);
|
||||
if (!_tabs[i].dialogName.empty()) {
|
||||
g_gui.xmlEval()->reflowDialogLayout(_tabs[i].dialogName, _tabs[i].firstWidget);
|
||||
g_gui.xmlEval()->reflowDialogLayout(_tabs[i].dialogName, _tabs[i].scrollWidget);
|
||||
}
|
||||
|
||||
Widget *w = _tabs[i].firstWidget;
|
||||
Widget *w = _tabs[i].scrollWidget;
|
||||
while (w) {
|
||||
w->reflowLayout();
|
||||
w = w->next();
|
||||
|
@ -396,7 +408,14 @@ void TabWidget::drawWidget() {
|
|||
}
|
||||
|
||||
void TabWidget::draw() {
|
||||
Widget::draw();
|
||||
if (_activeTab == -1) {
|
||||
Widget::draw();
|
||||
} else {
|
||||
_tabs[_activeTab].firstWidget = _firstWidget;
|
||||
_firstWidget = _tabs[_activeTab].scrollWidget;
|
||||
Widget::draw();
|
||||
_firstWidget = _tabs[_activeTab].firstWidget;
|
||||
}
|
||||
|
||||
if (_navButtonsVisible) {
|
||||
_navLeft->draw();
|
||||
|
|
|
@ -38,6 +38,7 @@ class TabWidget : public Widget {
|
|||
Common::U32String title;
|
||||
Common::String dialogName;
|
||||
Widget *firstWidget;
|
||||
ScrollContainerWidget *scrollWidget;
|
||||
int _tabWidth;
|
||||
};
|
||||
typedef Common::Array<Tab> TabList;
|
||||
|
@ -77,6 +78,8 @@ public:
|
|||
*/
|
||||
int addTab(const Common::U32String &title, const Common::String &dialogName);
|
||||
|
||||
virtual Widget *addChild(Widget *newChild);
|
||||
|
||||
/**
|
||||
* Remove the tab with the given tab ID. Disposes all child widgets of that tab.
|
||||
* TODO: This code is *unfinished*. In particular, it changes the
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue