aboutsummaryrefslogtreecommitdiff
path: root/gui
diff options
context:
space:
mode:
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