aboutsummaryrefslogtreecommitdiff
path: root/gui
diff options
context:
space:
mode:
authorWillem Jan Palenstijn2017-02-26 18:34:02 +0100
committerWillem Jan Palenstijn2017-02-28 15:55:52 +0100
commit5510640dbcd1bda6ae41942ed56c9ac037fc5228 (patch)
treebca82176d700bce72a948f046bc4acb43a740d98 /gui
parentaf831f26b97590024218801528f50e008f3b2f72 (diff)
downloadscummvm-rg350-5510640dbcd1bda6ae41942ed56c9ac037fc5228.tar.gz
scummvm-rg350-5510640dbcd1bda6ae41942ed56c9ac037fc5228.tar.bz2
scummvm-rg350-5510640dbcd1bda6ae41942ed56c9ac037fc5228.zip
GUI: Give each tab in TabWidget its own width
The width of each tab is now computed from its title, independently of the other tabs. This increases the number of tabs that fit on the screen. This rewrite also fixes a bug where if the window size increased while _firstVisibleTab > 0, some tabs would become inaccessible when the scroll buttons were hidden. The layout key Globals.TabWidget.Tab.Width is now treated as minimal tab width. This is set so that the tabs fit reasonably well in lowres layouts. At the same time, this reduces the lowres scroll buttons heights to fit. This patch makes the Nintento DS hacks in TabWidget obsolete. (Hopefully! I'm not able to test.)
Diffstat (limited to 'gui')
-rw-r--r--gui/ThemeEngine.cpp24
-rw-r--r--gui/ThemeEngine.h2
-rw-r--r--gui/themes/scummclassic.zipbin128803 -> 20021 bytes
-rw-r--r--gui/themes/scummclassic/classic_layout.stx2
-rw-r--r--gui/themes/scummclassic/classic_layout_lowres.stx4
-rw-r--r--gui/themes/scummmodern.zipbin1648343 -> 739209 bytes
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx2
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx4
-rw-r--r--gui/widgets/tab.cpp195
-rw-r--r--gui/widgets/tab.h15
10 files changed, 129 insertions, 119 deletions
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index d859a88da5..64b25d85f6 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -1620,28 +1620,34 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, co
}
}
-void ThemeEngine::drawTabClip(const Common::Rect &r, const Common::Rect &clip, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
+void ThemeEngine::drawTabClip(const Common::Rect &r, const Common::Rect &clip, int tabHeight, const Common::Array<int> &tabWidths, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) {
if (!ready())
return;
+ assert(tabs.size() == tabWidths.size());
+
queueDDClip(kDDTabBackground, Common::Rect(r.left, r.top, r.right, r.top + tabHeight), clip);
- for (int i = 0; i < (int)tabs.size(); ++i) {
- if (i == active)
+ int width = 0;
+ int activePos = -1;
+ for (int i = 0; i < (int)tabs.size(); width += tabWidths[i++]) {
+ if (r.left + width > r.right || r.left + width + tabWidths[i] > r.right)
continue;
- if (r.left + i * tabWidth > r.right || r.left + (i + 1) * tabWidth > r.right)
+ if (i == active) {
+ activePos = width;
continue;
+ }
- Common::Rect tabRect(r.left + i * tabWidth, r.top, r.left + (i + 1) * tabWidth, r.top + tabHeight);
+
+ Common::Rect tabRect(r.left + width, r.top, r.left + width + tabWidths[i], r.top + tabHeight);
queueDDClip(kDDTabInactive, tabRect, clip);
queueDDTextClip(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, clip, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV);
}
- if (active >= 0 &&
- (r.left + active * tabWidth < r.right) && (r.left + (active + 1) * tabWidth < r.right)) {
- Common::Rect tabRect(r.left + active * tabWidth, r.top, r.left + (active + 1) * tabWidth, r.top + tabHeight);
- const uint16 tabLeft = active * tabWidth;
+ if (activePos >= 0) {
+ Common::Rect tabRect(r.left + activePos, r.top, r.left + activePos + tabWidths[active], r.top + tabHeight);
+ const uint16 tabLeft = activePos;
const uint16 tabRight = MAX(r.right - tabRect.right, 0);
queueDDClip(kDDTabActive, tabRect, clip, (tabLeft << 16) | (tabRight & 0xFFFF));
queueDDTextClip(getTextData(kDDTabActive), getTextColor(kDDTabActive), tabRect, clip, tabs[active], false, false, _widgets[kDDTabActive]->_textAlignH, _widgets[kDDTabActive]->_textAlignV);
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 8a6db17dfd..9d8ed41738 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -388,7 +388,7 @@ public:
void drawTab(const Common::Rect &r, int tabHeight, int tabWidth,
const Common::Array<Common::String> &tabs, int active, uint16 hints,
int titleVPad, WidgetStateInfo state = kStateEnabled);
- void drawTabClip(const Common::Rect &r, const Common::Rect &clippingRect, int tabHeight, int tabWidth,
+ void drawTabClip(const Common::Rect &r, const Common::Rect &clippingRect, int tabHeight, const Common::Array<int> &tabWidths,
const Common::Array<Common::String> &tabs, int active, uint16 hints,
int titleVPad, WidgetStateInfo state = kStateEnabled);
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index e84768b497..8024437f6b 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx
index 75ffee20cd..35f4a03e6d 100644
--- a/gui/themes/scummclassic/classic_layout.stx
+++ b/gui/themes/scummclassic/classic_layout.stx
@@ -95,7 +95,7 @@
size = '15, 0'
/>
<widget name = 'TabWidget.Tab'
- size = '75, 27'
+ size = '40, 27'
padding = '0, 0, 8, 0'
/>
<widget name = 'TabWidget.Body'
diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx
index e46db3e94b..1085c5fc6f 100644
--- a/gui/themes/scummclassic/classic_layout_lowres.stx
+++ b/gui/themes/scummclassic/classic_layout_lowres.stx
@@ -93,14 +93,14 @@
size = '9, 0'
/>
<widget name = 'TabWidget.Tab'
- size = '45, 16'
+ size = '40, 16'
padding = '0, 0, 2, 0'
/>
<widget name = 'TabWidget.Body'
padding = '0, 0, 0, 0'
/>
<widget name = 'TabWidget.NavButton'
- size = '32, 18'
+ size = '32, 14'
padding = '0, 0, 1, 0'
/>
<widget name = 'EditRecordLabel'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index ed1e3c0c58..73aee35f61 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index 754bc251d9..9633cb4e50 100644
--- a/gui/themes/scummmodern/scummmodern_layout.stx
+++ b/gui/themes/scummmodern/scummmodern_layout.stx
@@ -98,7 +98,7 @@
size = '15, 0'
/>
<widget name = 'TabWidget.Tab'
- size = '75, 27'
+ size = '40, 27'
padding = '0, 0, 8, 0'
/>
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index eadb305414..be8ce0c17e 100644
--- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx
+++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
@@ -91,14 +91,14 @@
size = '9, 0'
/>
<widget name = 'TabWidget.Tab'
- size = '45, 16'
+ size = '40, 16'
padding = '0, 0, 2, 0'
/>
<widget name = 'TabWidget.Body'
padding = '0, 0, 0, 0'
/>
<widget name = 'TabWidget.NavButton'
- size = '32, 18'
+ size = '32, 14'
padding = '0, 0, 2, 0'
/>
<widget name = 'EditRecordLabel'
diff --git a/gui/widgets/tab.cpp b/gui/widgets/tab.cpp
index 8e8c6b48a1..c86c835b88 100644
--- a/gui/widgets/tab.cpp
+++ b/gui/widgets/tab.cpp
@@ -48,8 +48,10 @@ void TabWidget::init() {
_type = kTabWidget;
_activeTab = -1;
_firstVisibleTab = 0;
+ _lastVisibleTab = 0;
+ _navButtonsVisible = false;
- _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
+ _minTabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
_tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height");
_titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top");
@@ -105,52 +107,16 @@ int TabWidget::addTab(const String &title) {
newTab.title = title;
newTab.firstWidget = 0;
+ // Determine the new tab width
+ int newWidth = g_gui.getStringWidth(title) + 2 * 3;
+ if (newWidth < _minTabWidth)
+ newWidth = _minTabWidth;
+ newTab._tabWidth = newWidth;
+
_tabs.push_back(newTab);
int numTabs = _tabs.size();
- // HACK: Nintendo DS uses a custom config dialog. This dialog does not work with
- // our default "Globals.TabWidget.Tab.Width" setting.
- //
- // TODO: Add proper handling in the theme layout for such cases.
- //
- // There are different solutions to this problem:
- // - offer a "Tab.Width" setting per tab widget and thus let the Ninteno DS
- // backend set a default value for its special dialog.
- //
- // - change our themes to use auto width calculaction by default
- //
- // - change "Globals.TabWidget.Tab.Width" to be the minimal tab width setting and
- // rename it accordingly.
- // Actually this solution is pretty similar to our HACK for the Nintendo DS
- // backend. This hack enables auto width calculation by default with the
- // "Globals.TabWidget.Tab.Width" value as minimal width for the tab buttons.
- //
- // - we might also consider letting every tab button having its own width.
- //
- // - other solutions you can think of, which are hopefully less evil ;-).
- //
- // Of course also the Ninteno DS' dialog should be in our layouting engine, instead
- // of being hard coded like it is right now.
- //
- // There are checks for __DS__ all over this source file to take care of the
- // aforemnetioned problem.
-#ifdef __DS__
- if (true) {
-#else
- if (g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width") == 0) {
-#endif
- if (_tabWidth == 0)
- _tabWidth = 40;
- // Determine the new tab width
- int newWidth = g_gui.getStringWidth(title) + 2 * 3;
- if (_tabWidth < newWidth)
- _tabWidth = newWidth;
- int maxWidth = _w / numTabs;
- if (_tabWidth > maxWidth)
- _tabWidth = maxWidth;
- }
-
// Activate the new tab
setActiveTab(numTabs - 1);
@@ -160,7 +126,7 @@ int TabWidget::addTab(const String &title) {
void TabWidget::removeTab(int tabID) {
assert(0 <= tabID && tabID < (int)_tabs.size());
- // Deactive the tab if it's currently the active one
+ // Deactivate the tab if it's currently the active one
if (tabID == _activeTab) {
_tabs[tabID].firstWidget = _firstWidget;
releaseFocus();
@@ -202,9 +168,9 @@ void TabWidget::setActiveTab(int tabID) {
// Also ensure the tab is visible in the tab bar
if (_firstVisibleTab > tabID)
- _firstVisibleTab = tabID;
- else if (_firstVisibleTab + _w / _tabWidth <= tabID)
- _firstVisibleTab = tabID - _w / _tabWidth + 1;
+ setFirstVisible(tabID, true);
+ while (_lastVisibleTab < tabID)
+ setFirstVisible(_firstVisibleTab + 1, false);
_boss->draw();
}
@@ -216,16 +182,14 @@ void TabWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
switch (cmd) {
case kCmdLeft:
- if (_firstVisibleTab) {
- _firstVisibleTab--;
- draw();
+ if (_firstVisibleTab > 0) {
+ setFirstVisible(_firstVisibleTab - 1);
}
break;
case kCmdRight:
- if (_firstVisibleTab + _w / _tabWidth < (int)_tabs.size()) {
- _firstVisibleTab++;
- draw();
+ if (_lastVisibleTab + 1 < (int)_tabs.size()) {
+ setFirstVisible(_firstVisibleTab + 1, false);
}
break;
}
@@ -234,18 +198,20 @@ void TabWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
void TabWidget::handleMouseDown(int x, int y, int button, int clickCount) {
assert(y < _tabHeight);
+ if (x < 0)
+ return;
+
// Determine which tab was clicked
- int tabID = -1;
- if (x >= 0 && (x % _tabWidth) < _tabWidth) {
- tabID = x / _tabWidth;
- if (tabID >= (int)_tabs.size())
- tabID = -1;
+ int tabID;
+ for (tabID = _firstVisibleTab; tabID <= _lastVisibleTab; ++tabID) {
+ x -= _tabs[tabID]._tabWidth;
+ if (x < 0)
+ break;
}
// If a tab was clicked, switch to that pane
- if (tabID >= 0 && tabID + _firstVisibleTab < (int)_tabs.size()) {
- setActiveTab(tabID + _firstVisibleTab);
- }
+ if (tabID <= _lastVisibleTab)
+ setActiveTab(tabID);
}
bool TabWidget::handleKeyDown(Common::KeyState state) {
@@ -265,26 +231,20 @@ void TabWidget::adjustTabs(int value) {
else if (tabID < 0)
tabID = ((int)_tabs.size() - 1);
- // Slides _firstVisibleTab forward to the correct tab
- int maxTabsOnScreen = (_w / _tabWidth);
- if (tabID >= maxTabsOnScreen && (_firstVisibleTab + maxTabsOnScreen) < (int)_tabs.size())
- _firstVisibleTab++;
-
- // Slides _firstVisibleTab backwards to the correct tab
- while (tabID < _firstVisibleTab)
- _firstVisibleTab--;
-
setActiveTab(tabID);
}
-int TabWidget::getFirstVisible() {
+int TabWidget::getFirstVisible() const {
return _firstVisibleTab;
}
-void TabWidget::setFirstVisible(int tabID) {
+void TabWidget::setFirstVisible(int tabID, bool adjustIfRoom) {
assert(0 <= tabID && tabID < (int)_tabs.size());
_firstVisibleTab = tabID;
- _boss->draw();
+
+ computeLastVisibleTab(adjustIfRoom);
+
+ _boss->draw(); // TODO: Necessary?
}
void TabWidget::reflowLayout() {
@@ -293,9 +253,14 @@ void TabWidget::reflowLayout() {
// NOTE: if you change that, make sure to do the same
// changes in the ThemeLayoutTabWidget (gui/ThemeLayout.cpp)
_tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height");
- _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
+ _minTabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width");
_titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top");
+ _butRP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.PaddingRight", 0);
+ _butTP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Padding.Top", 0);
+ _butW = g_gui.xmlEval()->getVar("GlobalsTabWidget.NavButton.Width", 10);
+ _butH = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Height", 10);
+
// If widgets were added or removed in the current tab, without tabs
// having been switched using setActiveTab() afterward, then the
// firstWidget in the _tabs list for the active tab may not be up to
@@ -311,28 +276,34 @@ void TabWidget::reflowLayout() {
}
}
- if (_tabWidth == 0) {
- _tabWidth = 40;
-#ifdef __DS__
- }
- if (true) {
-#endif
- int maxWidth = _w / _tabs.size();
-
- for (uint i = 0; i < _tabs.size(); ++i) {
- // Determine the new tab width
- int newWidth = g_gui.getStringWidth(_tabs[i].title) + 2 * 3;
- if (_tabWidth < newWidth)
- _tabWidth = newWidth;
- if (_tabWidth > maxWidth)
- _tabWidth = maxWidth;
- }
+ for (uint i = 0; i < _tabs.size(); ++i) {
+ // Determine the new tab width
+ int newWidth = g_gui.getStringWidth(_tabs[i].title) + 2 * 3;
+ if (newWidth < _minTabWidth)
+ newWidth = _minTabWidth;
+ _tabs[i]._tabWidth = newWidth;
}
- _butRP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.PaddingRight", 0);
- _butTP = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Padding.Top", 0);
- _butW = g_gui.xmlEval()->getVar("GlobalsTabWidget.NavButton.Width", 10);
- _butH = g_gui.xmlEval()->getVar("Globals.TabWidget.NavButton.Height", 10);
+ // See how many tabs fit on screen.
+ // We do this in a loop, because it will change if we need to
+ // add left/right scroll buttons, if we scroll left to use free
+ // space on the right, or a combination of those.
+ _navButtonsVisible = _firstVisibleTab > 0;
+ do {
+ computeLastVisibleTab(true);
+
+ if (_firstVisibleTab > 0 || _lastVisibleTab + 1 < (int)_tabs.size()) {
+ if (!_navButtonsVisible)
+ _navButtonsVisible = true;
+ else
+ break;
+ } else {
+ if (_navButtonsVisible)
+ _navButtonsVisible = false;
+ else
+ break;
+ }
+ } while (true);
int x = _w - _butRP - _butW * 2 - 2;
int y = _butTP - _tabHeight;
@@ -342,18 +313,20 @@ void TabWidget::reflowLayout() {
void TabWidget::drawWidget() {
Common::Array<Common::String> tabs;
- for (int i = _firstVisibleTab; i < (int)_tabs.size(); ++i) {
+ Common::Array<int> widths;
+ for (int i = _firstVisibleTab; i <= _lastVisibleTab; ++i) {
tabs.push_back(_tabs[i].title);
+ widths.push_back(_tabs[i]._tabWidth);
}
g_gui.theme()->drawDialogBackgroundClip(Common::Rect(_x + _bodyLP, _y + _bodyTP, _x+_w-_bodyRP, _y+_h-_bodyBP+_tabHeight), getBossClipRect(), _bodyBackgroundType);
- g_gui.theme()->drawTabClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad);
+ g_gui.theme()->drawTabClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _tabHeight, widths, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad);
}
void TabWidget::draw() {
Widget::draw();
- if (_tabWidth * _tabs.size() > _w) {
+ if (_navButtonsVisible) {
_navLeft->draw();
_navRight->draw();
}
@@ -361,7 +334,7 @@ void TabWidget::draw() {
Widget *TabWidget::findWidget(int x, int y) {
if (y < _tabHeight) {
- if (_tabWidth * _tabs.size() > _w) {
+ if (_navButtonsVisible) {
if (y >= _butTP && y < _butTP + _butH) {
if (x >= _w - _butRP - _butW * 2 - 2 && x < _w - _butRP - _butW - 2)
return _navLeft;
@@ -378,4 +351,30 @@ Widget *TabWidget::findWidget(int x, int y) {
}
}
+void TabWidget::computeLastVisibleTab(bool adjustFirstIfRoom) {
+ int availableWidth = _w;
+ if (_navButtonsVisible)
+ availableWidth -= 2 + _butW * 2;
+
+ _lastVisibleTab = _tabs.size() - 1;
+ for (int i = _firstVisibleTab; i < (int)_tabs.size(); ++i) {
+ if (_tabs[i]._tabWidth > availableWidth) {
+ if (i > _firstVisibleTab)
+ _lastVisibleTab = i - 1;
+ else
+ _lastVisibleTab = _firstVisibleTab; // Always show 1
+ break;
+ }
+ availableWidth -= _tabs[i]._tabWidth;
+ }
+
+ if (adjustFirstIfRoom) {
+ // If possible, scroll to fit if there's unused space to the right
+ while (_firstVisibleTab > 0 && _tabs[_firstVisibleTab-1]._tabWidth <= availableWidth) {
+ availableWidth -= _tabs[_firstVisibleTab-1]._tabWidth;
+ _firstVisibleTab--;
+ }
+ }
+}
+
} // End of namespace GUI
diff --git a/gui/widgets/tab.h b/gui/widgets/tab.h
index 4516c3c831..a1a5e06481 100644
--- a/gui/widgets/tab.h
+++ b/gui/widgets/tab.h
@@ -39,15 +39,17 @@ class TabWidget : public Widget {
struct Tab {
String title;
Widget *firstWidget;
+ int _tabWidth;
};
typedef Common::Array<Tab> TabList;
protected:
int _activeTab;
int _firstVisibleTab;
+ int _lastVisibleTab;
TabList _tabs;
- int _tabWidth;
int _tabHeight;
+ int _minTabWidth;
int _bodyRP, _bodyTP, _bodyLP, _bodyBP;
ThemeEngine::DialogBackground _bodyBackgroundType;
@@ -57,6 +59,7 @@ protected:
int _butRP, _butTP, _butW, _butH;
ButtonWidget *_navLeft, *_navRight;
+ bool _navButtonsVisible;
public:
TabWidget(GuiObject *boss, int x, int y, int w, int h);
@@ -101,8 +104,8 @@ public:
virtual void handleMouseDown(int x, int y, int button, int clickCount);
virtual bool handleKeyDown(Common::KeyState state);
virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
- virtual int getFirstVisible();
- virtual void setFirstVisible(int tabID);
+ virtual int getFirstVisible() const;
+ virtual void setFirstVisible(int tabID, bool adjustIfRoom = false);
virtual void reflowLayout();
@@ -111,14 +114,16 @@ public:
protected:
// We overload getChildY to make sure child widgets are positioned correctly.
// Essentially this compensates for the space taken up by the tab title header.
- virtual int16 getChildY() const;
- virtual uint16 getHeight() const;
+ virtual int16 getChildY() const;
+ virtual uint16 getHeight() const;
virtual void drawWidget();
virtual Widget *findWidget(int x, int y);
virtual void adjustTabs(int value);
+
+ virtual void computeLastVisibleTab(bool adjustFirstIfRoom);
};
} // End of namespace GUI