diff options
-rw-r--r-- | gui/ThemeEngine.cpp | 24 | ||||
-rw-r--r-- | gui/ThemeEngine.h | 2 | ||||
-rw-r--r-- | gui/themes/scummclassic.zip | bin | 128803 -> 20021 bytes | |||
-rw-r--r-- | gui/themes/scummclassic/classic_layout.stx | 2 | ||||
-rw-r--r-- | gui/themes/scummclassic/classic_layout_lowres.stx | 4 | ||||
-rw-r--r-- | gui/themes/scummmodern.zip | bin | 1648343 -> 739209 bytes | |||
-rw-r--r-- | gui/themes/scummmodern/scummmodern_layout.stx | 2 | ||||
-rw-r--r-- | gui/themes/scummmodern/scummmodern_layout_lowres.stx | 4 | ||||
-rw-r--r-- | gui/widgets/tab.cpp | 195 | ||||
-rw-r--r-- | gui/widgets/tab.h | 15 |
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 Binary files differindex e84768b497..8024437f6b 100644 --- a/gui/themes/scummclassic.zip +++ b/gui/themes/scummclassic.zip 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 Binary files differindex ed1e3c0c58..73aee35f61 100644 --- a/gui/themes/scummmodern.zip +++ b/gui/themes/scummmodern.zip 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 |