diff options
Diffstat (limited to 'gui')
36 files changed, 935 insertions, 94 deletions
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index c2deb8c61e..c850a6a02e 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -121,6 +121,19 @@ protected: const WidgetDrawData *_data; }; +class ThemeItemDrawDataClip: public ThemeItem{ +public: + ThemeItemDrawDataClip(ThemeEngine *engine, const WidgetDrawData *data, const Common::Rect &area, const Common::Rect &clip, uint32 dynData) : + ThemeItem(engine, area), _dynamicData(dynData), _data(data), _clip(clip) {} + + void drawSelf(bool draw, bool restore); + +protected: + uint32 _dynamicData; + const WidgetDrawData *_data; + const Common::Rect _clip; +}; + class ThemeItemTextData : public ThemeItem { public: ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const TextColorData *color, const Common::Rect &area, const Common::Rect &textDrawableArea, @@ -155,7 +168,18 @@ protected: bool _alpha; }; +class ThemeItemBitmapClip : public ThemeItem { +public: + ThemeItemBitmapClip(ThemeEngine *engine, const Common::Rect &area, const Common::Rect &clip, const Graphics::Surface *bitmap, bool alpha) : + ThemeItem(engine, area), _bitmap(bitmap), _alpha(alpha), _clip(clip) {} + + void drawSelf(bool draw, bool restore); +protected: + const Graphics::Surface *_bitmap; + bool _alpha; + const Common::Rect _clip; +}; /********************************************************** * Data definitions for theme engine elements @@ -242,16 +266,40 @@ void ThemeItemDrawData::drawSelf(bool draw, bool restore) { _engine->addDirtyRect(extendedRect); } +void ThemeItemDrawDataClip::drawSelf(bool draw, bool restore) { + + Common::Rect extendedRect = _area; + extendedRect.grow(_engine->kDirtyRectangleThreshold + _data->_backgroundOffset); + + if (restore) + _engine->restoreBackground(extendedRect); + + if (draw) { + Common::List<Graphics::DrawStep>::const_iterator step; + for (step = _data->_steps.begin(); step != _data->_steps.end(); ++step) { + _engine->renderer()->drawStepClip(_area, _clip, *step, _dynamicData); + } + } + + extendedRect.clip(_clip); + + _engine->addDirtyRect(extendedRect); +} + void ThemeItemTextData::drawSelf(bool draw, bool restore) { + Common::Rect dirty = _textDrawableArea; + if (dirty.isEmpty()) dirty = _area; + else dirty.clip(_area); + if (_restoreBg || restore) - _engine->restoreBackground(_area); + _engine->restoreBackground(dirty); if (draw) { _engine->renderer()->setFgColor(_color->r, _color->g, _color->b); _engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis, _textDrawableArea); } - _engine->addDirtyRect(_area); + _engine->addDirtyRect(dirty); } void ThemeItemBitmap::drawSelf(bool draw, bool restore) { @@ -268,7 +316,21 @@ void ThemeItemBitmap::drawSelf(bool draw, bool restore) { _engine->addDirtyRect(_area); } +void ThemeItemBitmapClip::drawSelf(bool draw, bool restore) { + if (restore) + _engine->restoreBackground(_area); + if (draw) { + if (_alpha) + _engine->renderer()->blitAlphaBitmapClip(_bitmap, _area, _clip); + else + _engine->renderer()->blitSubSurfaceClip(_bitmap, _area, _clip); + } + + Common::Rect dirtyRect = _area; + dirtyRect.clip(_clip); + _engine->addDirtyRect(dirtyRect); +} /********************************************************** * ThemeEngine class @@ -311,6 +373,12 @@ ThemeEngine::ThemeEngine(Common::String id, GraphicsMode mode) : _themeArchive = 0; _initOk = false; + _cursorHotspotX = _cursorHotspotY = 0; + _cursorWidth = _cursorHeight = 0; + _cursorPalSize = 0; + + _needPaletteUpdates = false; + // We prefer files in archive bundles over the common search paths. _themeFiles.add("default", &SearchMan, 0, false); } @@ -558,7 +626,7 @@ void ThemeEngine::restoreBackground(Common::Rect r) { void ThemeEngine::addDrawStep(const Common::String &drawDataId, const Graphics::DrawStep &step) { DrawData id = parseDrawDataId(drawDataId); - assert(_widgets[id] != 0); + assert(id != kDDNone && _widgets[id] != 0); _widgets[id]->_steps.push_back(step); } @@ -856,10 +924,34 @@ void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic, } } +void ThemeEngine::queueDDClip(DrawData type, const Common::Rect &r, const Common::Rect &clippingRect, uint32 dynamic, bool restore) { + if (_widgets[type] == 0) + return; + + Common::Rect area = r; + area.clip(_screen.w, _screen.h); + + ThemeItemDrawDataClip *q = new ThemeItemDrawDataClip(this, _widgets[type], area, clippingRect, dynamic); + + if (_buffering) { + if (_widgets[type]->_buffer) { + _bufferQueue.push_back(q); + } else { + if (kDrawDataDefaults[type].parent != kDDNone && kDrawDataDefaults[type].parent != type) + queueDDClip(kDrawDataDefaults[type].parent, r, clippingRect); + + _screenQueue.push_back(q); + } + } else { + q->drawSelf(!_widgets[type]->_buffer, restore || _widgets[type]->_buffer); + delete q; + } +} + void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg, bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax, const Common::Rect &drawableTextArea) { - if (_texts[type] == 0) + if (type == kTextDataNone || _texts[type] == 0) return; Common::Rect area = r; @@ -875,6 +967,28 @@ void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect } } +void ThemeEngine::queueDDTextClip(TextData type, TextColor color, const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &text, bool restoreBg, + bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax, const Common::Rect &drawableTextArea) { + + if (_texts[type] == 0) + return; + + Common::Rect area = r; + area.clip(_screen.w, _screen.h); + Common::Rect textArea = drawableTextArea; + if (textArea.isEmpty()) textArea = clippingArea; + else textArea.clip(clippingArea); + + ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, textArea, text, alignH, alignV, ellipsis, restoreBg, deltax); + + if (_buffering) { + _screenQueue.push_back(q); + } else { + q->drawSelf(true, false); + delete q; + } +} + void ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha) { Common::Rect area = r; @@ -890,7 +1004,20 @@ void ThemeEngine::queueBitmap(const Graphics::Surface *bitmap, const Common::Rec } } +void ThemeEngine::queueBitmapClip(const Graphics::Surface *bitmap, const Common::Rect &r, const Common::Rect &clip, bool alpha) { + + Common::Rect area = r; + area.clip(_screen.w, _screen.h); + + ThemeItemBitmapClip *q = new ThemeItemBitmapClip(this, area, clip, bitmap, alpha); + if (_buffering) { + _screenQueue.push_back(q); + } else { + q->drawSelf(true, false); + delete q; + } +} /********************************************************** * Widget drawing functions @@ -914,6 +1041,25 @@ void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, W queueDDText(getTextData(dd), getTextColor(dd), r, str, false, true, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); } +void ThemeEngine::drawButtonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, WidgetStateInfo state, uint16 hints) { + if (!ready()) + return; + + DrawData dd = kDDButtonIdle; + + if (state == kStateEnabled) + dd = kDDButtonIdle; + else if (state == kStateHighlight) + dd = kDDButtonHover; + else if (state == kStateDisabled) + dd = kDDButtonDisabled; + else if (state == kStatePressed) + dd = kDDButtonPressed; + + queueDDClip(dd, r, clippingRect, 0, hints & WIDGET_CLEARBG); + queueDDTextClip(getTextData(dd), getTextColor(dd), r, clippingRect, str, false, true, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); +} + void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state) { if (!ready()) return; @@ -921,6 +1067,13 @@ void ThemeEngine::drawLineSeparator(const Common::Rect &r, WidgetStateInfo state queueDD(kDDSeparator, r); } +void ThemeEngine::drawLineSeparatorClip(const Common::Rect &r, const Common::Rect &clippingRect, WidgetStateInfo state) { + if (!ready()) + return; + + queueDDClip(kDDSeparator, r, clippingRect); +} + void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) { if (!ready()) return; @@ -947,6 +1100,32 @@ void ThemeEngine::drawCheckbox(const Common::Rect &r, const Common::String &str, queueDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV); } +void ThemeEngine::drawCheckboxClip(const Common::Rect &r, const Common::Rect &clip, const Common::String &str, bool checked, WidgetStateInfo state) { + if (!ready()) + return; + + Common::Rect r2 = r; + DrawData dd = kDDCheckboxDefault; + + if (checked) + dd = kDDCheckboxSelected; + + if (state == kStateDisabled) + dd = kDDCheckboxDisabled; + + const int checkBoxSize = MIN((int)r.height(), getFontHeight()); + + r2.bottom = r2.top + checkBoxSize; + r2.right = r2.left + checkBoxSize; + + queueDDClip(dd, r2, clip); + + r2.left = r2.right + checkBoxSize; + r2.right = r.right; + + queueDDTextClip(getTextData(dd), getTextColor(dd), r2, clip, str, true, false, _widgets[kDDCheckboxDefault]->_textAlignH, _widgets[dd]->_textAlignV); +} + void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state) { if (!ready()) return; @@ -973,6 +1152,32 @@ void ThemeEngine::drawRadiobutton(const Common::Rect &r, const Common::String &s queueDDText(getTextData(dd), getTextColor(dd), r2, str, true, false, _widgets[kDDRadiobuttonDefault]->_textAlignH, _widgets[dd]->_textAlignV); } +void ThemeEngine::drawRadiobuttonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, bool checked, WidgetStateInfo state) { + if (!ready()) + return; + + Common::Rect r2 = r; + DrawData dd = kDDRadiobuttonDefault; + + if (checked) + dd = kDDRadiobuttonSelected; + + if (state == kStateDisabled) + dd = kDDRadiobuttonDisabled; + + const int checkBoxSize = MIN((int)r.height(), getFontHeight()); + + r2.bottom = r2.top + checkBoxSize; + r2.right = r2.left + checkBoxSize; + + queueDDClip(dd, r2, clippingRect); + + r2.left = r2.right + checkBoxSize; + r2.right = r.right; + + queueDDTextClip(getTextData(dd), getTextColor(dd), r2, clippingRect, str, true, false, _widgets[kDDRadiobuttonDefault]->_textAlignH, _widgets[dd]->_textAlignV); +} + void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo state) { if (!ready()) return; @@ -993,6 +1198,26 @@ void ThemeEngine::drawSlider(const Common::Rect &r, int width, WidgetStateInfo s queueDD(dd, r2); } +void ThemeEngine::drawSliderClip(const Common::Rect &r, const Common::Rect &clip, int width, WidgetStateInfo state) { + if (!ready()) + return; + + DrawData dd = kDDSliderFull; + + if (state == kStateHighlight) + dd = kDDSliderHover; + else if (state == kStateDisabled) + dd = kDDSliderDisabled; + + Common::Rect r2 = r; + r2.setWidth(MIN((int16)width, r.width())); + // r2.top++; r2.bottom--; r2.left++; r2.right--; + + drawWidgetBackgroundClip(r, clip, 0, kWidgetBackgroundSlider, kStateEnabled); + + queueDDClip(dd, r2, clip); +} + void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) { if (!ready()) return; @@ -1014,11 +1239,34 @@ void ThemeEngine::drawScrollbar(const Common::Rect &r, int sliderY, int sliderHe r2.top += sliderY; r2.bottom = r2.top + sliderHeight; - r2.top += r.width() / 5; - r2.bottom -= r.width() / 5; + //r2.top += r.width() / 5; + //r2.bottom -= r.width() / 5; queueDD(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2); } +void ThemeEngine::drawScrollbarClip(const Common::Rect &r, const Common::Rect &clippingRect, int sliderY, int sliderHeight, ScrollbarState scrollState, WidgetStateInfo state) { + if (!ready()) + return; + + queueDDClip(kDDScrollbarBase, r, clippingRect); + + Common::Rect r2 = r; + const int buttonExtra = (r.width() * 120) / 100; + + r2.bottom = r2.top + buttonExtra; + queueDDClip(scrollState == kScrollbarStateUp ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, clippingRect, Graphics::VectorRenderer::kTriangleUp); + + r2.translate(0, r.height() - r2.height()); + queueDDClip(scrollState == kScrollbarStateDown ? kDDScrollbarButtonHover : kDDScrollbarButtonIdle, r2, clippingRect, Graphics::VectorRenderer::kTriangleDown); + + r2 = r; + r2.left += 1; + r2.right -= 1; + r2.top += sliderY; + r2.bottom = r2.top + sliderHeight; + queueDDClip(scrollState == kScrollbarStateSlider ? kDDScrollbarHandleHover : kDDScrollbarHandleIdle, r2, clippingRect); +} + void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground bgtype, WidgetStateInfo state) { if (!ready()) return; @@ -1046,6 +1294,33 @@ void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground b } } +void ThemeEngine::drawDialogBackgroundClip(const Common::Rect &r, const Common::Rect &clip, DialogBackground bgtype, WidgetStateInfo state) { + if (!ready()) + return; + + switch (bgtype) { + case kDialogBackgroundMain: + queueDDClip(kDDMainDialogBackground, r, clip); + break; + + case kDialogBackgroundSpecial: + queueDDClip(kDDSpecialColorBackground, r, clip); + break; + + case kDialogBackgroundPlain: + queueDDClip(kDDPlainColorBackground, r, clip); + break; + + case kDialogBackgroundTooltip: + queueDDClip(kDDTooltipBackground, r, clip); + break; + + case kDialogBackgroundDefault: + queueDDClip(kDDDefaultBackground, r, clip); + break; + } +} + void ThemeEngine::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state) { if (!ready()) return; @@ -1057,6 +1332,17 @@ void ThemeEngine::drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo s queueDD(kDDCaret, r); } +void ThemeEngine::drawCaretClip(const Common::Rect &r, const Common::Rect &clip, bool erase, WidgetStateInfo state) { + if (!ready()) + return; + + if (erase) { + restoreBackground(r); + addDirtyRect(r); + } else + queueDDClip(kDDCaret, r, clip); +} + void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state, Graphics::TextAlign align) { if (!ready()) return; @@ -1078,6 +1364,27 @@ void ThemeEngine::drawPopUpWidget(const Common::Rect &r, const Common::String &s } } +void ThemeEngine::drawPopUpWidgetClip(const Common::Rect &r, const Common::Rect &clip, const Common::String &sel, int deltax, WidgetStateInfo state, Graphics::TextAlign align) { + if (!ready()) + return; + + DrawData dd = kDDPopUpIdle; + + if (state == kStateEnabled) + dd = kDDPopUpIdle; + else if (state == kStateHighlight) + dd = kDDPopUpHover; + else if (state == kStateDisabled) + dd = kDDPopUpDisabled; + + queueDDClip(dd, r, clip); + + if (!sel.empty()) { + Common::Rect text(r.left + 3, r.top + 1, r.right - 10, r.bottom); + queueDDTextClip(getTextData(dd), getTextColor(dd), text, clip, sel, true, false, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV, deltax); + } +} + void ThemeEngine::drawSurface(const Common::Rect &r, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) { if (!ready()) return; @@ -1085,6 +1392,13 @@ void ThemeEngine::drawSurface(const Common::Rect &r, const Graphics::Surface &su queueBitmap(&surface, r, themeTrans); } +void ThemeEngine::drawSurfaceClip(const Common::Rect &r, const Common::Rect &clip, const Graphics::Surface &surface, WidgetStateInfo state, int alpha, bool themeTrans) { + if (!ready()) + return; + + queueBitmapClip(&surface, r, clip, themeTrans); +} + void ThemeEngine::drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background, WidgetStateInfo state) { if (!ready()) return; @@ -1108,6 +1422,29 @@ void ThemeEngine::drawWidgetBackground(const Common::Rect &r, uint16 hints, Widg } } +void ThemeEngine::drawWidgetBackgroundClip(const Common::Rect &r, const Common::Rect &clip, uint16 hints, WidgetBackground background, WidgetStateInfo state) { + if (!ready()) + return; + + switch (background) { + case kWidgetBackgroundBorderSmall: + queueDDClip(kDDWidgetBackgroundSmall, r, clip); + break; + + case kWidgetBackgroundEditText: + queueDDClip(kDDWidgetBackgroundEditText, r, clip); + break; + + case kWidgetBackgroundSlider: + queueDDClip(kDDWidgetBackgroundSlider, r, clip); + break; + + default: + queueDDClip(kDDWidgetBackgroundDefault, r, clip); + break; + } +} + void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array<Common::String> &tabs, int active, uint16 hints, int titleVPad, WidgetStateInfo state) { if (!ready()) return; @@ -1136,6 +1473,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) { + if (!ready()) + return; + + 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) + continue; + + if (r.left + i * tabWidth > r.right || r.left + (i + 1) * tabWidth > r.right) + continue; + + Common::Rect tabRect(r.left + i * tabWidth, r.top, r.left + (i + 1) * tabWidth, 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; + 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); + } +} + void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore, const Common::Rect &drawableTextArea) { if (!ready()) return; @@ -1209,6 +1574,79 @@ void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, Wid queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax, drawableTextArea); } +void ThemeEngine::drawTextClip(const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore, const Common::Rect &drawableTextArea) { + if (!ready()) + return; + + TextColor colorId = kTextColorMAX; + + switch (color) { + case kFontColorNormal: + if (inverted) { + colorId = kTextColorNormalInverted; + } else { + switch (state) { + case kStateDisabled: + colorId = kTextColorNormalDisabled; + break; + + case kStateHighlight: + colorId = kTextColorNormalHover; + break; + + case kStateEnabled: + case kStatePressed: + colorId = kTextColorNormal; + break; + } + } + break; + + case kFontColorAlternate: + if (inverted) { + colorId = kTextColorAlternativeInverted; + } else { + switch (state) { + case kStateDisabled: + colorId = kTextColorAlternativeDisabled; + break; + + case kStateHighlight: + colorId = kTextColorAlternativeHover; + break; + + case kStateEnabled: + case kStatePressed: + colorId = kTextColorAlternative; + break; + } + } + break; + + default: + return; + } + + TextData textId = fontStyleToData(font); + + switch (inverted) { + case kTextInversion: + queueDDClip(kDDTextSelectionBackground, r, clippingArea); + restore = false; + break; + + case kTextInversionFocus: + queueDDClip(kDDTextSelectionFocusBackground, r, clippingArea); + restore = false; + break; + + default: + break; + } + + queueDDTextClip(textId, colorId, r, clippingArea, str, restore, useEllipsis, align, kTextAlignVCenter, deltax, drawableTextArea); +} + void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) { if (!ready()) return; @@ -1223,6 +1661,21 @@ void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font addDirtyRect(charArea); } +void ThemeEngine::drawCharClip(const Common::Rect &r, const Common::Rect &clip, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) { + if (!ready()) + return; + + Common::Rect charArea = r; + charArea.clip(_screen.w, _screen.h); + if (!clip.isEmpty()) charArea.clip(clip); + + uint32 rgbColor = _overlayFormat.RGBToColor(_textColors[color]->r, _textColors[color]->g, _textColors[color]->b); + + restoreBackground(charArea); + font->drawChar(&_screen, ch, charArea.left, charArea.top, rgbColor); + addDirtyRect(charArea); +} + void ThemeEngine::debugWidgetPosition(const char *name, const Common::Rect &r) { _font->drawString(&_screen, name, r.left, r.top, r.width(), 0xFFFF, Graphics::kTextAlignRight, 0, true); _screen.hLine(r.left, r.top, r.right, 0xFFFF); @@ -1259,8 +1712,15 @@ void ThemeEngine::updateScreen(bool render) { _screenQueue.clear(); } - if (render) + if (render) { +#ifdef LAYOUT_DEBUG_DIALOG + _vectorRenderer->fillSurface(); + _themeEval->debugDraw(&_screen, _font); + _vectorRenderer->copyWholeFrame(_system); +#else renderDirtyScreen(); +#endif + } } void ThemeEngine::addDirtyRect(Common::Rect r) { diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index a5ef49c78b..3c259b4f9d 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -340,42 +340,67 @@ public: void drawWidgetBackground(const Common::Rect &r, uint16 hints, WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled); + void drawWidgetBackgroundClip(const Common::Rect &r, const Common::Rect &clippingArea, uint16 hints, + WidgetBackground background = kWidgetBackgroundPlain, WidgetStateInfo state = kStateEnabled); void drawButton(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, uint16 hints = 0); + void drawButtonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, + WidgetStateInfo state = kStateEnabled, uint16 hints = 0); void drawSurface(const Common::Rect &r, const Graphics::Surface &surface, - WidgetStateInfo state = kStateEnabled, int alpha = 256, bool themeTrans = false); + WidgetStateInfo state = kStateEnabled, int alpha = 255, bool themeTrans = false); + void drawSurfaceClip(const Common::Rect &r, const Common::Rect &clippingRect, const Graphics::Surface &surface, + WidgetStateInfo state = kStateEnabled, int alpha = 255, bool themeTrans = false); void drawSlider(const Common::Rect &r, int width, WidgetStateInfo state = kStateEnabled); + void drawSliderClip(const Common::Rect &r, const Common::Rect &clippingRect, int width, + WidgetStateInfo state = kStateEnabled); void drawCheckbox(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state = kStateEnabled); + void drawCheckboxClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, + bool checked, WidgetStateInfo state = kStateEnabled); void drawRadiobutton(const Common::Rect &r, const Common::String &str, bool checked, WidgetStateInfo state = kStateEnabled); + void drawRadiobuttonClip(const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &str, + bool checked, WidgetStateInfo state = kStateEnabled); 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, + const Common::Array<Common::String> &tabs, int active, uint16 hints, + int titleVPad, WidgetStateInfo state = kStateEnabled); void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state = kStateEnabled); + void drawScrollbarClip(const Common::Rect &r, const Common::Rect &clippingRect, int sliderY, int sliderHeight, + ScrollbarState scrollState, WidgetStateInfo state = kStateEnabled); void drawPopUpWidget(const Common::Rect &r, const Common::String &sel, int deltax, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignLeft); + void drawPopUpWidgetClip(const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &sel, + int deltax, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignLeft); void drawCaret(const Common::Rect &r, bool erase, WidgetStateInfo state = kStateEnabled); + void drawCaretClip(const Common::Rect &r, const Common::Rect &clip, bool erase, + WidgetStateInfo state = kStateEnabled); void drawLineSeparator(const Common::Rect &r, WidgetStateInfo state = kStateEnabled); + void drawLineSeparatorClip(const Common::Rect &r, const Common::Rect &clippingArea, WidgetStateInfo state = kStateEnabled); void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled); + void drawDialogBackgroundClip(const Common::Rect &r, const Common::Rect &clip, DialogBackground type, WidgetStateInfo state = kStateEnabled); void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal, bool restore = true, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0)); + void drawTextClip(const Common::Rect &r, const Common::Rect &clippingArea, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal, bool restore = true, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0)); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled, FontColor color = kFontColorNormal); + void drawCharClip(const Common::Rect &r, const Common::Rect &clippingArea, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled, FontColor color = kFontColorNormal); //@} @@ -584,9 +609,13 @@ protected: * This function is called from all the Widget Drawing methods. */ void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0, bool restore = false); + void queueDDClip(DrawData type, const Common::Rect &r, const Common::Rect &clippingRect, uint32 dynamic = 0, bool restore = false); void queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg, bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0)); + void queueDDTextClip(TextData type, TextColor color, const Common::Rect &r, const Common::Rect &clippingRect, const Common::String &text, bool restoreBg, + bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0)); void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha); + void queueBitmapClip(const Graphics::Surface *bitmap, const Common::Rect &clippingRect, const Common::Rect &r, bool alpha); /** * DEBUG: Draws a white square and writes some text next to it. diff --git a/gui/ThemeEval.cpp b/gui/ThemeEval.cpp index 9d57d2408b..5255587089 100644 --- a/gui/ThemeEval.cpp +++ b/gui/ThemeEval.cpp @@ -91,10 +91,18 @@ void ThemeEval::addWidget(const Common::String &name, int w, int h, const Common typeAlign = (Graphics::TextAlign)getVar("Globals." + type + ".Align", Graphics::kTextAlignInvalid); } - ThemeLayoutWidget *widget = new ThemeLayoutWidget(_curLayout.top(), name, - typeW == -1 ? w : typeW, - typeH == -1 ? h : typeH, - typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign); + ThemeLayoutWidget *widget; + if (type == "TabWidget") + widget = new ThemeLayoutTabWidget(_curLayout.top(), name, + typeW == -1 ? w : typeW, + typeH == -1 ? h : typeH, + typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign, + getVar("Globals.TabWidget.Tab.Height", 0)); + else + widget = new ThemeLayoutWidget(_curLayout.top(), name, + typeW == -1 ? w : typeW, + typeH == -1 ? h : typeH, + typeAlign == Graphics::kTextAlignInvalid ? align : typeAlign); _curLayout.top()->addChild(widget); setVar(_curDialog + "." + name + ".Enabled", enabled ? 1 : 0); diff --git a/gui/ThemeLayout.cpp b/gui/ThemeLayout.cpp index 6a6fd9e343..71e4b2c9fd 100644 --- a/gui/ThemeLayout.cpp +++ b/gui/ThemeLayout.cpp @@ -123,7 +123,7 @@ int16 ThemeLayoutStacked::getParentHeight() { #ifdef LAYOUT_DEBUG_DIALOG void ThemeLayout::debugDraw(Graphics::Surface *screen, const Graphics::Font *font) { - uint16 color = 0xFFFF; + uint32 color = 0xFFFFFFFF; font->drawString(screen, getName(), _x, _y, _w, color, Graphics::kTextAlignRight, 0, true); screen->hLine(_x, _y, _x + _w, color); screen->hLine(_x, _y + _h, _x + _w , color); diff --git a/gui/ThemeLayout.h b/gui/ThemeLayout.h index ba28fae1ac..e738002aa6 100644 --- a/gui/ThemeLayout.h +++ b/gui/ThemeLayout.h @@ -29,7 +29,7 @@ #ifdef LAYOUT_DEBUG_DIALOG namespace Graphics { -class Surface; +struct Surface; } #endif @@ -45,7 +45,8 @@ public: kLayoutMain, kLayoutVertical, kLayoutHorizontal, - kLayoutWidget + kLayoutWidget, + kLayoutTabWidget }; ThemeLayout(ThemeLayout *p) : @@ -223,6 +224,41 @@ protected: Common::String _name; }; +class ThemeLayoutTabWidget : public ThemeLayoutWidget { + int _tabHeight; + +public: + ThemeLayoutTabWidget(ThemeLayout *p, const Common::String &name, int16 w, int16 h, Graphics::TextAlign align, int tabHeight): + ThemeLayoutWidget(p, name, w, h, align) { + _tabHeight = tabHeight; + } + + void reflowLayout() { + for (uint i = 0; i < _children.size(); ++i) { + _children[i]->resetLayout(); + _children[i]->reflowLayout(); + } + } + + virtual bool getWidgetData(const Common::String &name, int16 &x, int16 &y, uint16 &w, uint16 &h) { + if (ThemeLayoutWidget::getWidgetData(name, x, y, w, h)) { + h -= _tabHeight; + return true; + } + + return false; + } + +protected: + LayoutType getLayoutType() { return kLayoutTabWidget; } + + ThemeLayout *makeClone(ThemeLayout *newParent) { + ThemeLayoutTabWidget *n = new ThemeLayoutTabWidget(*this); + n->_parent = newParent; + return n; + } +}; + class ThemeLayoutSpacing : public ThemeLayout { public: ThemeLayoutSpacing(ThemeLayout *p, int size) : ThemeLayout(p) { diff --git a/gui/Tooltip.cpp b/gui/Tooltip.cpp index ba313ee34f..09ad7ce5ca 100644 --- a/gui/Tooltip.cpp +++ b/gui/Tooltip.cpp @@ -32,7 +32,7 @@ namespace GUI { Tooltip::Tooltip() : - Dialog(-1, -1, -1, -1), _maxWidth(-1) { + Dialog(-1, -1, -1, -1), _maxWidth(-1), _parent(NULL), _xdelta(0), _ydelta(0) { _backgroundType = GUI::ThemeEngine::kDialogBackgroundTooltip; } diff --git a/gui/credits.h b/gui/credits.h index d1d3bb2147..c2c4c84ec6 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -58,6 +58,7 @@ static const char *credits[] = { "C1""AGI", "C0""Stuart George", "C0""Matthew Hoops", +"C2""(retired)", "C0""Filippos Karapetis", "C0""Martin Kiewitz", "C0""Pawel Kolodziejski", @@ -127,6 +128,7 @@ static const char *credits[] = { "C1""Drascula", "C0""Filippos Karapetis", "C0""Pawel Kolodziejski", +"C0""Thierry Crozat", "", "C1""DreamWeb", "A0""Torbjorn Andersson", @@ -137,6 +139,11 @@ static const char *credits[] = { "C2""(retired)", "C0""Willem Jan Palenstijn", "", +"C1""Gnap", +"A0""Arnaud Boutonne", +"C0""Arnaud Boutonn\351", +"C0""Benjamin Haisch", +"", "C1""Gob", "A0""Torbjorn Andersson", "C0""Torbj\366rn Andersson", @@ -173,6 +180,7 @@ static const char *credits[] = { "", "C1""Lastexpress", "C0""Matthew Hoops", +"C2""(retired)", "C0""Jordi Vilalta Prat", "C0""Julien Templier", "", @@ -192,6 +200,7 @@ static const char *credits[] = { "C1""Mohawk", "C0""Bastien Bouclet", "C0""Matthew Hoops", +"C2""(retired)", "C0""Filippos Karapetis", "C0""Alyssa Milburn", "C0""Eugene Sandulenko", @@ -211,6 +220,7 @@ static const char *credits[] = { "", "C1""Pegasus", "C0""Matthew Hoops", +"C2""(retired)", "", "C1""Queen", "C0""David Eriksson", @@ -343,6 +353,7 @@ static const char *credits[] = { "C1""Android", "C0""Andre Heider", "C0""Angus Lees", +"C0""Lubomyr Lisen", "", "C1""Dreamcast", "C0""Marcus Comstedt", @@ -366,6 +377,9 @@ static const char *credits[] = { "C2""(retired)", "C0""Tarek Soliman", "", +"C1""Nintendo 3DS", +"C0""Thomas Edvalson", +"", "C1""Nintendo 64", "C0""Fabio Battaglia", "", @@ -477,7 +491,7 @@ static const char *credits[] = { "C0""Joachim Eberhard", "C2""Numerous contributions to documentation (retired)", "C0""Matthew Hoops", -"C2""Wiki editor", +"C2""Numerous contributions to documentation (retired)", "", "C1""Retired Team Members", "C0""Chris Apers", diff --git a/gui/dialog.cpp b/gui/dialog.cpp index 075a3bb533..523227a237 100644 --- a/gui/dialog.cpp +++ b/gui/dialog.cpp @@ -51,6 +51,8 @@ Dialog::Dialog(int x, int y, int w, int h) // will for example crash after returning to the launcher when the user // started a 640x480 game with a non 1x scaler. g_gui.checkScreenChange(); + + _result = -1; } Dialog::Dialog(const Common::String &name) @@ -66,6 +68,8 @@ Dialog::Dialog(const Common::String &name) // Fixes bug #1590596: "HE: When 3x graphics are choosen, F5 crashes game" // and bug #1595627: "SCUMM: F5 crashes game (640x480)" g_gui.checkScreenChange(); + + _result = -1; } int Dialog::runModal() { @@ -109,13 +113,13 @@ void Dialog::reflowLayout() { // changed, so any cached image may be invalid. The subsequent redraw // should be treated as the very first draw. + GuiObject::reflowLayout(); + Widget *w = _firstWidget; while (w) { w->reflowLayout(); w = w->_next; } - - GuiObject::reflowLayout(); } void Dialog::lostFocus() { diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp index 3ce8bee020..9acd9434ff 100644 --- a/gui/gui-manager.cpp +++ b/gui/gui-manager.cpp @@ -564,6 +564,12 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi } } +void GuiManager::doFullRedraw() { + _redrawStatus = kRedrawFull; + redraw(); + _system->updateScreen(); +} + void GuiManager::giveFocusToDialog(Dialog *dialog) { int16 dialogX = _globalMousePosition.x - dialog->_x; int16 dialogY = _globalMousePosition.y - dialog->_y; diff --git a/gui/gui-manager.h b/gui/gui-manager.h index 35779215b2..4dc9af95fb 100644 --- a/gui/gui-manager.h +++ b/gui/gui-manager.h @@ -73,6 +73,7 @@ public: void runLoop(); void processEvent(const Common::Event &event, Dialog *const activeDialog); + void doFullRedraw(); bool isActive() const { return ! _dialogStack.empty(); } diff --git a/gui/launcher.cpp b/gui/launcher.cpp index bae894cba1..9a3300b11f 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -282,6 +282,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc) // // 6) The MIDI tab // + _globalMIDIOverride = NULL; if (!_guioptions.contains(GUIO_NOMIDI)) { tab->addTab(_("MIDI")); @@ -296,6 +297,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc) // // 7) The MT-32 tab // + _globalMT32Override = NULL; if (!_guioptions.contains(GUIO_NOMIDI)) { tab->addTab(_("MT-32")); diff --git a/gui/module.mk b/gui/module.mk index 9e821e71a7..6cbc63d24d 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -30,6 +30,7 @@ MODULE_OBJS := \ widgets/list.o \ widgets/popup.o \ widgets/scrollbar.o \ + widgets/scrollcontainer.o \ widgets/tab.o # HACK: create_project's XCode generator relies on the following ifdef diff --git a/gui/object.cpp b/gui/object.cpp index ef2cc9d6e0..de66d95492 100644 --- a/gui/object.cpp +++ b/gui/object.cpp @@ -44,19 +44,6 @@ void GuiObject::reflowLayout() { if (!g_gui.xmlEval()->getWidgetData(_name, _x, _y, _w, _h)) { error("Could not load widget position for '%s'", _name.c_str()); } - - if (_x < 0) - error("Widget <%s> has x < 0 (%d)", _name.c_str(), _x); - if (_x >= g_gui.getWidth()) - error("Widget <%s> has x > %d (%d)", _name.c_str(), g_gui.getWidth(), _x); - if (_x + _w > g_gui.getWidth()) - error("Widget <%s> has x + w > %d (%d)", _name.c_str(), g_gui.getWidth(), _x + _w); - if (_y < 0) - error("Widget <%s> has y < 0 (%d)", _name.c_str(), _y); - if (_y >= g_gui.getHeight()) - error("Widget <%s> has y > %d (%d)", _name.c_str(), g_gui.getHeight(), _y); - if (_y + _h > g_gui.getHeight()) - error("Widget <%s> has y + h > %d (%d)", _name.c_str(), g_gui.getHeight(), _y + _h); } } diff --git a/gui/options.cpp b/gui/options.cpp index 2bb17509eb..e410971818 100644 --- a/gui/options.cpp +++ b/gui/options.cpp @@ -112,6 +112,7 @@ void OptionsDialog::init() { _fullscreenCheckbox = 0; _aspectCheckbox = 0; _enableAudioSettings = false; + _midiTabId = 0; _midiPopUp = 0; _midiPopUpDesc = 0; _oplPopUp = 0; @@ -144,6 +145,7 @@ void OptionsDialog::init() { _speechVolumeSlider = 0; _speechVolumeLabel = 0; _muteCheckbox = 0; + _enableSubtitleSettings = false; _subToggleDesc = 0; _subToggleGroup = 0; _subToggleSubOnly = 0; @@ -152,6 +154,8 @@ void OptionsDialog::init() { _subSpeedDesc = 0; _subSpeedSlider = 0; _subSpeedLabel = 0; + + _pathsTabId = 0; _oldTheme = g_gui.theme()->getThemeId(); // Retrieve game GUI options @@ -209,7 +213,7 @@ void OptionsDialog::open() { #ifdef GUI_ONLY_FULLSCREEN _fullscreenCheckbox->setState(true); _fullscreenCheckbox->setEnabled(false); - _aspectCheckbox->setState(false); + _aspectCheckbox->setState(ConfMan.getBool("aspect_ratio", _domain)); _aspectCheckbox->setEnabled(false); #else // !GUI_ONLY_FULLSCREEN // Fullscreen setting diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp index 63b69a39ea..933667186e 100644 --- a/gui/predictivedialog.cpp +++ b/gui/predictivedialog.cpp @@ -142,6 +142,9 @@ PredictiveDialog::PredictiveDialog() : Dialog("Predictive") { _numMemory = 0; _navigationWithKeys = false; + + _curPressedButton = kNoAct; + _needRefresh = true; } PredictiveDialog::~PredictiveDialog() { diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp index a333c5fe57..3d4adfff2b 100644 --- a/gui/saveload-dialog.cpp +++ b/gui/saveload-dialog.cpp @@ -932,6 +932,8 @@ SavenameDialog::SavenameDialog() new ButtonWidget(this, "SavenameDialog.Ok", _("OK"), 0, kOKCmd); _description = new EditTextWidget(this, "SavenameDialog.Description", Common::String(), 0, 0, kOKCmd); + + _targetSlot = 0; } void SavenameDialog::setDescription(const Common::String &desc) { diff --git a/gui/themes/default.inc b/gui/themes/default.inc index a23e2f4c30..c0ea733de8 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -798,7 +798,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "</dialog>" "<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'>" "<layout type='vertical' padding='0,0,0,0'>" -"<widget name='TabWidget'/>" +"<widget name='TabWidget' type='TabWidget'/>" "<layout type='horizontal' padding='16,16,16,16'>" "<space/>" "<widget name='Cancel' " @@ -1118,7 +1118,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "</dialog>" "<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'>" "<layout type='vertical' padding='0,0,0,0' spacing='16'>" -"<widget name='TabWidget'/>" +"<widget name='TabWidget' type='TabWidget'/>" "<layout type='horizontal' padding='16,16,16,4'>" "<space/>" "<widget name='Cancel' " @@ -1405,7 +1405,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "</dialog>" "<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>" "<layout type='vertical' padding='0,0,0,0'>" -"<widget name='TabWidget'/>" +"<widget name='TabWidget' type='TabWidget'/>" "<layout type='horizontal' padding='16,16,16,16'>" "<space/>" "<widget name='ResetSettings' " @@ -1975,7 +1975,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "padding='0,0,2,0' " "/>" "<widget name='TabWidget.Body' " -"padding='0,0,0,-8' " +"padding='0,0,0,0' " "/>" "<widget name='TabWidget.NavButton' " "size='32,18' " @@ -2093,7 +2093,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "</dialog>" "<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'>" "<layout type='vertical' padding='0,0,0,0'>" -"<widget name='TabWidget'/>" +"<widget name='TabWidget' type='TabWidget'/>" "<layout type='horizontal' padding='8,8,8,8'>" "<space/>" "<widget name='Cancel' " @@ -2420,7 +2420,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "</dialog>" "<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'>" "<layout type='vertical' padding='0,0,0,0' spacing='16'>" -"<widget name='TabWidget'/>" +"<widget name='TabWidget' type='TabWidget'/>" "<layout type='horizontal' padding='8,8,8,8'>" "<space/>" "<widget name='Cancel' " @@ -2716,7 +2716,7 @@ const char *defaultXML1 = "<?xml version = '1.0'?>" "</dialog>" "<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>" "<layout type='vertical' padding='0,0,0,0'>" -"<widget name='TabWidget'/>" +"<widget name='TabWidget' type='TabWidget'/>" "<layout type='horizontal' padding='8,8,8,8'>" "<space/>" "<widget name='ResetSettings' " diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differindex 43fcea12fd..561f2a5dd3 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 65724d9faf..5172326859 100644 --- a/gui/themes/scummclassic/classic_layout.stx +++ b/gui/themes/scummclassic/classic_layout.stx @@ -222,7 +222,7 @@ <dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '16, 16, 16, 16'> <space/> <widget name = 'Cancel' @@ -551,7 +551,7 @@ <dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '16, 16, 16, 4'> <space/> <widget name = 'Cancel' @@ -850,7 +850,7 @@ <dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '16, 16, 16, 16'> <space/> <widget name = 'ResetSettings' diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index f73f6e864b..0013b91ee2 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -97,7 +97,7 @@ padding = '0, 0, 2, 0' /> <widget name = 'TabWidget.Body' - padding = '0, 0, 0, -8' + padding = '0, 0, 0, 0' /> <widget name = 'TabWidget.NavButton' size = '32, 18' @@ -219,7 +219,7 @@ <dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '8, 8, 8, 8'> <space/> <widget name = 'Cancel' @@ -556,7 +556,7 @@ <dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '8, 8, 8, 8'> <space/> <widget name = 'Cancel' @@ -863,7 +863,7 @@ <dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '8, 8, 8, 8'> <space/> <widget name = 'ResetSettings' diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip Binary files differindex 70f7672c57..d80c481ffc 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 c73ffa1f08..026fa7bc64 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -236,7 +236,7 @@ <dialog name = 'GlobalOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '16, 16, 16, 16'> <space/> <widget name = 'Cancel' @@ -565,7 +565,7 @@ <dialog name = 'GameOptions' overlays = 'Dialog.Launcher.GameList' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '16, 16, 16, 4'> <space/> <widget name = 'Cancel' @@ -864,7 +864,7 @@ <dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '16, 16, 16, 16'> <space/> <widget name = 'ResetSettings' diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index 43ec0cdee1..169e61a9bb 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -95,7 +95,7 @@ padding = '0, 0, 2, 0' /> <widget name = 'TabWidget.Body' - padding = '0, 0, 0, -8' + padding = '0, 0, 0, 0' /> <widget name = 'TabWidget.NavButton' size = '32, 18' @@ -217,7 +217,7 @@ <dialog name = 'GlobalOptions' overlays = 'screen' inset = '16' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '8, 8, 8, 8'> <space/> <widget name = 'Cancel' @@ -554,7 +554,7 @@ <dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '8, 8, 8, 8'> <space/> <widget name = 'Cancel' @@ -861,7 +861,7 @@ <dialog name = 'FluidSynthSettings' overlays = 'GlobalOptions' shading = 'dim'> <layout type = 'vertical' padding = '0, 0, 0, 0'> - <widget name = 'TabWidget'/> + <widget name = 'TabWidget' type = 'TabWidget'/> <layout type = 'horizontal' padding = '8, 8, 8, 8'> <space/> <widget name = 'ResetSettings' diff --git a/gui/themes/translations.dat b/gui/themes/translations.dat Binary files differindex 917acdb13d..7533d41454 100644 --- a/gui/themes/translations.dat +++ b/gui/themes/translations.dat diff --git a/gui/updates-dialog.cpp b/gui/updates-dialog.cpp index 960b3f397a..b82ecc0402 100644 --- a/gui/updates-dialog.cpp +++ b/gui/updates-dialog.cpp @@ -76,13 +76,13 @@ UpdatesDialog::UpdatesDialog() : Dialog(30, 20, 260, 124) { _y = (screenH - _h) / 2; // Each line is represented by one static text item. - int y = 10; - for (int i = 0; i < lines.size(); i++) { + uint y = 10; + for (uint i = 0; i < lines.size(); i++) { new StaticTextWidget(this, 10, y, maxlineWidth, kLineHeight, lines[i], Graphics::kTextAlignCenter); y += kLineHeight; } - for (int i = 0; i < lines2.size(); i++) { + for (uint i = 0; i < lines2.size(); i++) { new StaticTextWidget(this, 10, y, maxlineWidth2, kLineHeight, lines2[i], Graphics::kTextAlignCenter, 0, ThemeEngine::kFontStyleTooltip); y += kLineHeight; diff --git a/gui/widget.cpp b/gui/widget.cpp index 03540f7b91..f2a29c3100 100644 --- a/gui/widget.cpp +++ b/gui/widget.cpp @@ -53,6 +53,31 @@ void Widget::init() { _boss->_firstWidget = this; } +Common::Rect Widget::getBossClipRect() const { + int bx = _boss->getAbsX(); + int by = _boss->getAbsY(); + Common::Rect result = Common::Rect(bx, by, bx + _boss->getWidth(), by + _boss->getHeight()); + bool needsClipping = false; + + //check whether clipping area is inside the screen + if (result.left < 0 && (needsClipping = true)) + warning("Widget <%s> has clipping area x < 0 (%d)", _name.c_str(), result.left); + if (result.left >= g_gui.getWidth() && (needsClipping = true)) + warning("Widget <%s> has clipping area x > %d (%d)", _name.c_str(), g_gui.getWidth(), result.left); + if (result.right > g_gui.getWidth() && (needsClipping = true)) + warning("Widget <%s> has clipping area x + w > %d (%d)", _name.c_str(), g_gui.getWidth(), result.right); + if (result.top < 0 && (needsClipping = true)) + warning("Widget <%s> has clipping area y < 0 (%d)", _name.c_str(), result.top); + if (result.top >= g_gui.getHeight() && (needsClipping = true)) + warning("Widget <%s> has clipping area y > %d (%d)", _name.c_str(), g_gui.getHeight(), result.top); + if (result.bottom > g_gui.getHeight() && (needsClipping = true)) + warning("Widget <%s> has clipping area y + h > %d (%d)", _name.c_str(), g_gui.getHeight(), result.bottom); + + if (needsClipping) + result.clip(g_gui.getWidth(), g_gui.getHeight()); + return result; +} + Widget::~Widget() { delete _next; _next = 0; @@ -99,7 +124,7 @@ void Widget::draw() { // Draw border if (_flags & WIDGET_BORDER) { - g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, ThemeEngine::kWidgetBackgroundBorder); + g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder); _x += 4; _y += 4; _w -= 8; @@ -131,7 +156,7 @@ void Widget::draw() { Widget *Widget::findWidgetInChain(Widget *w, int x, int y) { while (w) { // Stop as soon as we find a widget that contains the point (x,y) - if (x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->_h) + if (x >= w->_x && x < w->_x + w->_w && y >= w->_y && y < w->_y + w->getHeight()) break; w = w->_next; } @@ -265,14 +290,25 @@ void StaticTextWidget::setLabel(const Common::String &label) { } void StaticTextWidget::setAlign(Graphics::TextAlign align) { - _align = align; - // TODO: We should automatically redraw when the alignment is changed. - // See setLabel() for more insights. + if (_align != align){ + _align = align; + + // same as setLabel() actually, the text + // would be redrawn on top of the old one so + // we add the CLEARBG flag + setFlags(WIDGET_CLEARBG); + draw(); + clearFlags(WIDGET_CLEARBG); + } + } void StaticTextWidget::drawWidget() { - g_gui.theme()->drawText(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, _align, ThemeEngine::kTextInversionNone, 0, true, _font); + g_gui.theme()->drawTextClip( + Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), + _label, _state, _align, ThemeEngine::kTextInversionNone, 0, true, _font + ); } #pragma mark - @@ -311,7 +347,10 @@ void ButtonWidget::handleMouseDown(int x, int y, int button, int clickCount) { } void ButtonWidget::drawWidget() { - g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, getFlags()); + g_gui.theme()->drawButtonClip( + Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), + _label, _state, getFlags() + ); } void ButtonWidget::setLabel(const Common::String &label) { @@ -410,7 +449,7 @@ void PicButtonWidget::setGfx(int w, int h, int r, int g, int b) { } void PicButtonWidget::drawWidget() { - g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), "", _state, getFlags()); + g_gui.theme()->drawButtonClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), "", _state, getFlags()); if (_gfx.getPixels()) { // Check whether the set up surface needs to be converted to the GUI @@ -423,7 +462,7 @@ void PicButtonWidget::drawWidget() { const int x = _x + (_w - _gfx.w) / 2; const int y = _y + (_h - _gfx.h) / 2; - g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency); + g_gui.theme()->drawSurfaceClip(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), getBossClipRect(), _gfx, _state, _alpha, _transparency); } } @@ -458,7 +497,7 @@ void CheckboxWidget::setState(bool state) { } void CheckboxWidget::drawWidget() { - g_gui.theme()->drawCheckbox(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, Widget::_state); + g_gui.theme()->drawCheckboxClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _label, _state, Widget::_state); } #pragma mark - @@ -527,21 +566,21 @@ void RadiobuttonWidget::setState(bool state, bool setGroup) { } void RadiobuttonWidget::drawWidget() { - g_gui.theme()->drawRadiobutton(Common::Rect(_x, _y, _x+_w, _y+_h), _label, _state, Widget::_state); + g_gui.theme()->drawRadiobuttonClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _label, _state, Widget::_state); } #pragma mark - SliderWidget::SliderWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip, uint32 cmd) : Widget(boss, x, y, w, h, tooltip), CommandSender(boss), - _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false) { + _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false), _labelWidth(0) { setFlags(WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG); _type = kSliderWidget; } SliderWidget::SliderWidget(GuiObject *boss, const Common::String &name, const char *tooltip, uint32 cmd) : Widget(boss, name, tooltip), CommandSender(boss), - _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false) { + _cmd(cmd), _value(0), _oldValue(0), _valueMin(0), _valueMax(100), _isDragging(false), _labelWidth(0) { setFlags(WIDGET_ENABLED | WIDGET_TRACK_MOUSE | WIDGET_CLEARBG); _type = kSliderWidget; } @@ -595,7 +634,7 @@ void SliderWidget::handleMouseWheel(int x, int y, int direction) { } void SliderWidget::drawWidget() { - g_gui.theme()->drawSlider(Common::Rect(_x, _y, _x + _w, _y + _h), valueToBarWidth(_value), _state); + g_gui.theme()->drawSliderClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), valueToBarWidth(_value), _state); } int SliderWidget::valueToBarWidth(int value) { @@ -672,7 +711,7 @@ void GraphicsWidget::drawWidget() { const int x = _x + (_w - _gfx.w) / 2; const int y = _y + (_h - _gfx.h) / 2; - g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency); + g_gui.theme()->drawSurfaceClip(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), getBossClipRect(), _gfx, _state, _alpha, _transparency); } } @@ -709,7 +748,7 @@ void ContainerWidget::removeWidget(Widget *widget) { } void ContainerWidget::drawWidget() { - g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorder); + g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder); } } // End of namespace GUI diff --git a/gui/widget.h b/gui/widget.h index 7f6f0c0533..0f4b300233 100644 --- a/gui/widget.h +++ b/gui/widget.h @@ -68,7 +68,8 @@ enum { kPopUpWidget = 'POPU', kTabWidget = 'TABW', kGraphicsWidget = 'GFXW', - kContainerWidget = 'CTNR' + kContainerWidget = 'CTNR', + kScrollContainerWidget = 'SCTR' }; enum { @@ -111,6 +112,7 @@ public: virtual int16 getAbsX() const { return _x + _boss->getChildX(); } virtual int16 getAbsY() const { return _y + _boss->getChildY(); } + virtual Common::Rect getBossClipRect() const; virtual void setPos(int x, int y) { _x = x; _y = y; } virtual void setSize(int w, int h) { _w = w; _h = h; } diff --git a/gui/widgets/editable.cpp b/gui/widgets/editable.cpp index 2d929113b1..4f7e584c14 100644 --- a/gui/widgets/editable.cpp +++ b/gui/widgets/editable.cpp @@ -274,7 +274,7 @@ void EditableWidget::drawCaret(bool erase) { x += getAbsX(); y += getAbsY(); - g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height()), erase); + g_gui.theme()->drawCaretClip(Common::Rect(x, y, x + 1, y + editRect.height()), getBossClipRect(), erase); if (erase) { GUI::EditableWidget::String character; @@ -303,7 +303,7 @@ void EditableWidget::drawCaret(bool erase) { // possible glitches due to different methods used. width = MIN(editRect.width() - caretOffset, width); if (width > 0) { - g_gui.theme()->drawText(Common::Rect(x, y, x + width, y + editRect.height()), character, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); + g_gui.theme()->drawTextClip(Common::Rect(x, y, x + width, y + editRect.height()), getBossClipRect(), character, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); } } diff --git a/gui/widgets/edittext.cpp b/gui/widgets/edittext.cpp index 1481bebae3..0a8725ac9e 100644 --- a/gui/widgets/edittext.cpp +++ b/gui/widgets/edittext.cpp @@ -36,6 +36,8 @@ EditTextWidget::EditTextWidget(GuiObject *boss, int x, int y, int w, int h, cons setEditString(text); setFontStyle(ThemeEngine::kFontStyleNormal); + + _leftPadding = _rightPadding = 0; } EditTextWidget::EditTextWidget(GuiObject *boss, const String &name, const String &text, const char *tooltip, uint32 cmd, uint32 finishCmd) @@ -46,6 +48,8 @@ EditTextWidget::EditTextWidget(GuiObject *boss, const String &name, const String setEditString(text); setFontStyle(ThemeEngine::kFontStyleNormal); + + _leftPadding = _rightPadding = 0; } void EditTextWidget::setEditString(const String &str) { @@ -93,7 +97,7 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) { } void EditTextWidget::drawWidget() { - g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x+_w, _y+_h), 0, ThemeEngine::kWidgetBackgroundEditText); + g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundEditText); // Draw the text adjustOffset(); @@ -101,7 +105,7 @@ void EditTextWidget::drawWidget() { const Common::Rect &r = Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 8, _y + _h); setTextDrawableArea(r); - g_gui.theme()->drawText(Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 2, _y + _h), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); + g_gui.theme()->drawTextClip(Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 2, _y + _h), getBossClipRect(), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); } Common::Rect EditTextWidget::getEditRect() const { diff --git a/gui/widgets/list.cpp b/gui/widgets/list.cpp index 4b69202fdc..f6e5c67510 100644 --- a/gui/widgets/list.cpp +++ b/gui/widgets/list.cpp @@ -488,7 +488,7 @@ void ListWidget::drawWidget() { Common::String buffer; // Draw a thin frame around the list. - g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorder); + g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder); const int scrollbarW = (_scrollBar && _scrollBar->isVisible()) ? _scrollBarWidth : 0; // Draw the list items @@ -507,7 +507,7 @@ void ListWidget::drawWidget() { // If in numbering mode, we first print a number prefix if (_numberingMode != kListNumberingOff) { buffer = Common::String::format("%2d. ", (pos + _numberingMode)); - g_gui.theme()->drawText(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2), + g_gui.theme()->drawTextClip(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2), getBossClipRect(), buffer, _state, Graphics::kTextAlignLeft, inverted, _leftPadding, true); pad = 0; } @@ -528,12 +528,12 @@ void ListWidget::drawWidget() { color = _editColor; adjustOffset(); width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW; - g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state, + g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), getBossClipRect(), buffer, _state, Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color); } else { buffer = _list[pos]; width = _w - r.left - scrollbarW; - g_gui.theme()->drawText(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), buffer, _state, + g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), getBossClipRect(), buffer, _state, Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color); } diff --git a/gui/widgets/popup.cpp b/gui/widgets/popup.cpp index b10b4fb5fe..82f4112a97 100644 --- a/gui/widgets/popup.cpp +++ b/gui/widgets/popup.cpp @@ -71,6 +71,10 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY) : Dialog(0, 0, 16, 16), _popUpBoss(boss) { + _openTime = 0; + _buffer = nullptr; + _entriesPerColumn = 1; + // Copy the selection index _selection = _popUpBoss->_selectedItem; @@ -142,8 +146,6 @@ PopUpDialog::PopUpDialog(PopUpWidget *boss, int clickX, int clickY) // Remember original mouse position _clickX = clickX - _x; _clickY = clickY - _y; - - _openTime = 0; } void PopUpDialog::drawDialog() { @@ -362,8 +364,11 @@ void PopUpDialog::drawMenuEntry(int entry, bool hilite) { // Draw a separator g_gui.theme()->drawLineSeparator(Common::Rect(x, y, x+w, y+kLineHeight)); } else { - g_gui.theme()->drawText(Common::Rect(x+1, y+2, x+w, y+2+kLineHeight), name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled, - Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, _leftPadding); + g_gui.theme()->drawText( + Common::Rect(x+1, y+2, x+w, y+2+kLineHeight), + name, hilite ? ThemeEngine::kStateHighlight : ThemeEngine::kStateEnabled, + Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, _leftPadding + ); } } @@ -380,6 +385,7 @@ PopUpWidget::PopUpWidget(GuiObject *boss, const String &name, const char *toolti _type = kPopUpWidget; _selectedItem = -1; + _leftPadding = _rightPadding = 0; } PopUpWidget::PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip) @@ -388,6 +394,8 @@ PopUpWidget::PopUpWidget(GuiObject *boss, int x, int y, int w, int h, const char _type = kPopUpWidget; _selectedItem = -1; + + _leftPadding = _rightPadding = 0; } void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount) { @@ -465,7 +473,10 @@ void PopUpWidget::drawWidget() { Common::String sel; if (_selectedItem >= 0) sel = _entries[_selectedItem].name; - g_gui.theme()->drawPopUpWidget(Common::Rect(_x, _y, _x + _w, _y + _h), sel, _leftPadding, _state, Graphics::kTextAlignLeft); + g_gui.theme()->drawPopUpWidgetClip( + Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), + sel, _leftPadding, _state, Graphics::kTextAlignLeft + ); } } // End of namespace GUI diff --git a/gui/widgets/scrollbar.cpp b/gui/widgets/scrollbar.cpp index f1306b9c4a..d8bcb18336 100644 --- a/gui/widgets/scrollbar.cpp +++ b/gui/widgets/scrollbar.cpp @@ -26,6 +26,7 @@ #include "gui/widgets/scrollbar.h" #include "gui/gui-manager.h" #include "gui/ThemeEngine.h" +#include "gui/widgets/scrollcontainer.h" namespace GUI { @@ -202,7 +203,11 @@ void ScrollBarWidget::drawWidget() { state = ThemeEngine::kScrollbarStateSlider; } - g_gui.theme()->drawScrollbar(Common::Rect(_x, _y, _x+_w, _y+_h), _sliderPos, _sliderHeight, state, _state); + Common::Rect clipRect = getBossClipRect(); + //scrollbar is not a usual child of ScrollContainerWidget, so it gets this special treatment + if (dynamic_cast<ScrollContainerWidget *>(_boss)) + clipRect.right += _w; + g_gui.theme()->drawScrollbarClip(Common::Rect(_x, _y, _x+_w, _y+_h), clipRect, _sliderPos, _sliderHeight, state, _state); } } // End of namespace GUI diff --git a/gui/widgets/scrollcontainer.cpp b/gui/widgets/scrollcontainer.cpp new file mode 100644 index 0000000000..1b38478c11 --- /dev/null +++ b/gui/widgets/scrollcontainer.cpp @@ -0,0 +1,147 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/util.h" +#include "gui/widgets/scrollcontainer.h" +#include "gui/gui-manager.h" + +#include "gui/ThemeEval.h" + +namespace GUI { + +ScrollContainerWidget::ScrollContainerWidget(GuiObject *boss, int x, int y, int w, int h) + : Widget(boss, x, y, w, h) { + init(); +} + +ScrollContainerWidget::ScrollContainerWidget(GuiObject *boss, const Common::String &name) + : Widget(boss, name) { + init(); +} + +void ScrollContainerWidget::init() { + setFlags(WIDGET_ENABLED); + _type = kScrollContainerWidget; + _verticalScroll = new ScrollBarWidget(this, _w-16, 0, 16, _h); + _verticalScroll->setTarget(this); + _scrolledX = 0; + _scrolledY = 0; + _limitH = 140; + recalc(); +} + +void ScrollContainerWidget::recalc() { + int scrollbarWidth = g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0); + _limitH = _h; + + //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) { + if (ptr != _verticalScroll) { + int y = ptr->getAbsY() - getChildY(); + min = MIN(min, y - spacing); + max = MAX(max, y + ptr->getHeight() + spacing); + } + ptr = ptr->next(); + } + h = max - min; + + _verticalScroll->_numEntries = h; + _verticalScroll->_currentPos = _scrolledY; + _verticalScroll->_entriesPerPage = _limitH; + _verticalScroll->setPos(_w - scrollbarWidth, _scrolledY+1); + _verticalScroll->setSize(scrollbarWidth, _limitH -2); +} + + +ScrollContainerWidget::~ScrollContainerWidget() {} + +int16 ScrollContainerWidget::getChildX() const { + return getAbsX() - _scrolledX; +} + +int16 ScrollContainerWidget::getChildY() const { + return getAbsY() - _scrolledY; +} + +uint16 ScrollContainerWidget::getWidth() const { + return _w - (_verticalScroll->isVisible() ? _verticalScroll->getWidth() : 0); +} + +uint16 ScrollContainerWidget::getHeight() const { + return _limitH; +} + +void ScrollContainerWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { + Widget::handleCommand(sender, cmd, data); + switch (cmd) { + case kSetPositionCmd: + _scrolledY = _verticalScroll->_currentPos; + reflowLayout(); + draw(); + g_gui.doFullRedraw(); + break; + } +} + +void ScrollContainerWidget::reflowLayout() { + Widget::reflowLayout(); + + //reflow layout of inner widgets + Widget *ptr = _firstWidget; + while (ptr) { + ptr->reflowLayout(); + ptr = ptr->next(); + } + + //recalculate height + recalc(); + + //hide those widgets which are out of visible area + ptr = _firstWidget; + while (ptr) { + int y = ptr->getAbsY() - getChildY(); + int h = ptr->getHeight(); + bool visible = true; + if (y + h - _scrolledY < 0) visible = false; + if (y - _scrolledY > _limitH) visible = false; + ptr->setVisible(visible); + ptr = ptr->next(); + } + + _verticalScroll->setVisible(_verticalScroll->_numEntries > _limitH); //show when there is something to scroll +} + +void ScrollContainerWidget::drawWidget() { + g_gui.theme()->drawDialogBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + getHeight() - 1), getBossClipRect(), ThemeEngine::kDialogBackgroundDefault); +} + +Widget *ScrollContainerWidget::findWidget(int x, int y) { + if (_verticalScroll->isVisible() && x >= _w - _verticalScroll->getWidth()) + return _verticalScroll; + return Widget::findWidgetInChain(_firstWidget, x + _scrolledX, y + _scrolledY); +} + +} // End of namespace GUI diff --git a/gui/widgets/scrollcontainer.h b/gui/widgets/scrollcontainer.h new file mode 100644 index 0000000000..692c7e3507 --- /dev/null +++ b/gui/widgets/scrollcontainer.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef GUI_WIDGETS_SCROLLCONTAINER_H +#define GUI_WIDGETS_SCROLLCONTAINER_H + +#include "gui/widget.h" +#include "common/str.h" +#include "scrollbar.h" + +namespace GUI { + +class ScrollContainerWidget: public Widget { + ScrollBarWidget *_verticalScroll; + int16 _scrolledX, _scrolledY; + uint16 _limitH; + + void recalc(); + +public: + ScrollContainerWidget(GuiObject *boss, int x, int y, int w, int h); + ScrollContainerWidget(GuiObject *boss, const Common::String &name); + ~ScrollContainerWidget(); + + void init(); + virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); + virtual void reflowLayout(); + +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 getChildX() const; + virtual int16 getChildY() const; + virtual uint16 getWidth() const; + virtual uint16 getHeight() const; + + virtual void drawWidget(); + + virtual Widget *findWidget(int x, int y); +}; + +} // End of namespace GUI + +#endif diff --git a/gui/widgets/tab.cpp b/gui/widgets/tab.cpp index 756781a04b..15e6a9d370 100644 --- a/gui/widgets/tab.cpp +++ b/gui/widgets/tab.cpp @@ -80,9 +80,19 @@ TabWidget::~TabWidget() { } int16 TabWidget::getChildY() const { + // NOTE: if you change that, make sure to do the same + // changes in the ThemeLayoutTabWidget (gui/ThemeLayout.cpp) return getAbsY() + _tabHeight; } +uint16 TabWidget::getHeight() const { + // NOTE: if you change that, make sure to do the same + // changes in the ThemeLayoutTabWidget (gui/ThemeLayout.cpp) + // NOTE: this height is used for clipping, so it *includes* + // tabs, because it starts from getAbsY(), not getChildY() + return _h + _tabHeight; +} + int TabWidget::addTab(const String &title) { // Add a new tab page Tab newTab; @@ -258,6 +268,12 @@ void TabWidget::adjustTabs(int value) { void TabWidget::reflowLayout() { Widget::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"); + _titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top"); + for (uint i = 0; i < _tabs.size(); ++i) { Widget *w = _tabs[i].firstWidget; while (w) { @@ -266,10 +282,6 @@ void TabWidget::reflowLayout() { } } - _tabHeight = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Height"); - _tabWidth = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Width"); - _titleVPad = g_gui.xmlEval()->getVar("Globals.TabWidget.Tab.Padding.Top"); - if (_tabWidth == 0) { _tabWidth = 40; #ifdef __DS__ @@ -304,9 +316,9 @@ void TabWidget::drawWidget() { for (int i = _firstVisibleTab; i < (int)_tabs.size(); ++i) { tabs.push_back(_tabs[i].title); } - g_gui.theme()->drawDialogBackground(Common::Rect(_x + _bodyLP, _y + _bodyTP, _x+_w-_bodyRP, _y+_h-_bodyBP), _bodyBackgroundType); + g_gui.theme()->drawDialogBackgroundClip(Common::Rect(_x + _bodyLP, _y + _bodyTP, _x+_w-_bodyRP, _y+_h-_bodyBP+_tabHeight), getBossClipRect(), _bodyBackgroundType); - g_gui.theme()->drawTab(Common::Rect(_x, _y, _x+_w, _y+_h), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad); + g_gui.theme()->drawTabClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), _tabHeight, _tabWidth, tabs, _activeTab - _firstVisibleTab, 0, _titleVPad); } void TabWidget::draw() { diff --git a/gui/widgets/tab.h b/gui/widgets/tab.h index 148f164fbb..17b85986b5 100644 --- a/gui/widgets/tab.h +++ b/gui/widgets/tab.h @@ -110,6 +110,7 @@ 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 void drawWidget(); |