From 80412a4139d19024a9ef941004380e6bbb8d4da9 Mon Sep 17 00:00:00 2001 From: Alexander Tkachev Date: Wed, 29 Jun 2016 21:07:12 +0600 Subject: GUI: Add drawTabClip() --- graphics/VectorRenderer.h | 5 +- graphics/VectorRendererSpec.cpp | 291 ++++++++++++++++++++++++++++++++++++++++ graphics/VectorRendererSpec.h | 13 +- gui/ThemeEngine.cpp | 28 ++++ gui/ThemeEngine.h | 3 + gui/widgets/tab.cpp | 4 +- 6 files changed, 339 insertions(+), 5 deletions(-) diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index bedc8a3a8f..af275c59fd 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -218,6 +218,7 @@ public: * @param r Radius of the corners of the tab (0 for squared tabs). */ virtual void drawTab(int x, int y, int r, int w, int h) = 0; + virtual void drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping) = 0; /** @@ -404,10 +405,10 @@ public: drawBeveledSquareClip(x, y, w, h, _bevel, clip); } - void drawCallback_TAB(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { //TODO + void drawCallback_TAB(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { uint16 x, y, w, h; stepGetPositions(step, area, x, y, w, h); - drawTab(x, y, stepGetRadius(step, area), w, h); + drawTabClip(x, y, stepGetRadius(step, area), w, h, clip); } void drawCallback_BITMAP(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) { //TODO diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 607b9a37b1..672ca3416b 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -1425,6 +1425,66 @@ drawTab(int x, int y, int r, int w, int h) { } } +template +void VectorRendererSpec:: +drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping) { + if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h || + w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h) + return; + + Common::Rect backup = _clippingArea; + _clippingArea = clipping; + bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h))); + + if (r == 0 && Base::_bevel > 0) { + if (useClippingVersions) + drawBevelTabAlgClip(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + else + drawBevelTabAlg(x, y, w, h, Base::_bevel, _bevelColor, _fgColor, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + _clippingArea = backup; + return; + } + + if (r == 0) { + _clippingArea = backup; + return; + } + + switch (Base::_fillMode) { + case kFillDisabled: + // FIXME: Implement this + _clippingArea = backup; + return; + + case kFillGradient: + case kFillBackground: + // FIXME: This is broken for the AA renderer. + // See the rounded rect alg for how to fix it. (The border should + // be drawn before the interior, both inside drawTabAlg.) + if (useClippingVersions) { + drawTabShadowClip(x, y, w - 2, h, r); + drawTabAlgClip(x, y, w - 2, h, r, _bgColor, Base::_fillMode); + if (Base::_strokeWidth) + drawTabAlgClip(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + } else { + drawTabShadow(x, y, w - 2, h, r); + drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode); + if (Base::_strokeWidth) + drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); + } + break; + + case kFillForeground: + if (useClippingVersions) + drawTabAlgClip(x, y, w, h, r, _fgColor, Base::_fillMode); + else + drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode); + break; + } + + _clippingArea = backup; +} + template void VectorRendererSpec:: drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) { @@ -1685,6 +1745,120 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer: } } +template +void VectorRendererSpec:: +drawTabAlgClip(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer::FillMode fill_m, int baseLeft, int baseRight) { + // Don't draw anything for empty rects. + if (w <= 0 || h <= 0) { + return; + } + + int f, ddF_x, ddF_y; + int x, y, px, py; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int sw = 0, sp = 0, hp = 0; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + int tl_x = x1 + r, tl_y = y1 + r; + int tr_x = x1 + w - r, tr_y = y1 + r; + int fill_x = x1, fill_y = y1; + + int real_radius = r; + int short_h = h - r + 2; + int long_h = h; + + if (fill_m == kFillDisabled) { + while (sw++ < Base::_strokeWidth) { + colorFillClip(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, fill_x + r, fill_y + sp/pitch, _clippingArea); + colorFillClip(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, fill_x + r, fill_y + hp / pitch - sp / pitch, _clippingArea); + sp += pitch; + + BE_RESET(); + r--; + + while (x++ < y) { + BE_ALGORITHM(); + BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y); + + if (Base::_strokeWidth > 1) + BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px - pitch, py, tr_x, tr_y, tl_x, tl_y); + } + } + + ptr_fill += pitch * real_radius; + fill_y += real_radius; + while (short_h--) { + colorFillClip(ptr_fill, ptr_fill + Base::_strokeWidth, color, fill_x, fill_y, _clippingArea); + colorFillClip(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, fill_x + w - Base::_strokeWidth + 1, fill_y, _clippingArea); + ptr_fill += pitch; + ++fill_y; + } + + if (baseLeft) { + sw = 0; + ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1 + h + 1); + fill_x = x1; + fill_y = y1 + h + 1; + while (sw++ < Base::_strokeWidth) { + colorFillClip(ptr_fill - baseLeft, ptr_fill, color, fill_x - baseLeft, fill_y, _clippingArea); + ptr_fill += pitch; + ++fill_y; + } + } + + if (baseRight) { + sw = 0; + ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w, y1 + h + 1); + fill_x = x1 + w; + fill_y = y1 + h + 1; + while (sw++ < Base::_strokeWidth) { + colorFillClip(ptr_fill, ptr_fill + baseRight, color, fill_x, fill_y, _clippingArea); + ptr_fill += pitch; + ++fill_y; + } + } + } else { + BE_RESET(); + + precalcGradient(long_h); + + PixelType color1, color2; + color1 = color2 = color; + + while (x++ < y) { + BE_ALGORITHM(); + + if (fill_m == kFillGradient) { + color1 = calcGradient(real_radius - x, long_h); + color2 = calcGradient(real_radius - y, long_h); + + gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y, tl_x - x, tl_y - y); + gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x, tl_x - y, tl_y - x); + + BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y); + } else { + colorFillClip(ptr_tl - x - py, ptr_tr + x - py, color, tl_x - x, tl_y - y, _clippingArea); + colorFillClip(ptr_tl - y - px, ptr_tr + y - px, color, tl_x - y, tl_y - x, _clippingArea); + + BE_DRAWCIRCLE_TOP_CLIP(ptr_tr, ptr_tl, x, y, px, py, tr_x, tr_y, tl_x, tl_y); + } + } + + ptr_fill += pitch * r; + fill_y += r; + while (short_h--) { + if (fill_m == kFillGradient) { + gradientFillClip(ptr_fill, w + 1, x1, real_radius++, fill_x, fill_y); + } else { + colorFillClip(ptr_fill, ptr_fill + w + 1, color, fill_x, fill_y, _clippingArea); + } + ptr_fill += pitch; + ++fill_y; + } + } +} template void VectorRendererSpec:: @@ -1747,6 +1921,72 @@ drawTabShadow(int x1, int y1, int w, int h, int r) { } } +template +void VectorRendererSpec:: +drawTabShadowClip(int x1, int y1, int w, int h, int r) { + int offset = 3; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + + // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) + uint8 expFactor = 3; + uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; + + int xstart = x1; + int ystart = y1; + int width = w; + int height = h + offset + 1; + + for (int i = offset; i >= 0; i--) { + int f, ddF_x, ddF_y; + int x, y, px, py; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + + int tl_x = xstart + r, tl_y = ystart + r; + int fill_x = xstart, fill_y = ystart; + + int short_h = height - (2 * r) + 2; + PixelType color = _format.RGBToColor(0, 0, 0); + + BE_RESET(); + + // HACK: As we are drawing circles exploting 8-axis symmetry, + // there are 4 pixels on each circle which are drawn twice. + // this is ok on filled circles, but when blending on surfaces, + // we cannot let it blend twice. awful. + uint32 hb = 0; + + while (x++ < y) { + BE_ALGORITHM(); + + if (((1 << x) & hb) == 0) { + blendFillClip(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha, tl_x - y, tl_y - x); + hb |= (1 << x); + } + + if (((1 << y) & hb) == 0) { + blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, tl_x - x, tl_y - y); + hb |= (1 << y); + } + } + + ptr_fill += pitch * r; + fill_y += r; + while (short_h--) { + blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha, fill_x, fill_y); + ptr_fill += pitch; + ++fill_y; + } + + // Move shadow one pixel upward each iteration + xstart += 1; + // Multiply with expfactor + alpha = (alpha * (expFactor << 8)) >> 9; + } +} + /** BEVELED TABS FOR CLASSIC THEME **/ template void VectorRendererSpec:: @@ -1791,6 +2031,57 @@ drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, Pixe } } +template +void VectorRendererSpec:: +drawBevelTabAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, int baseLeft, int baseRight) { + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int i, j; + + PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); + int ptr_x = x, ptr_y = y; + + i = bevel; + while (i--) { + colorFillClip(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + + if (baseLeft > 0) { + i = h - bevel; + ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y); + ptr_x = x; ptr_y = y; + while (i--) { + colorFillClip(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } + } + + i = h - bevel; + j = bevel - 1; + ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y); + ptr_x = x + w - bevel; ptr_y = y; + while (i--) { + colorFillClip(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea); + if (j > 0) j--; + ptr_left += pitch; + ++ptr_y; + } + + i = bevel; + ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y + h - bevel); + ptr_x = x + w - bevel; ptr_y = y + h - bevel; + while (i--) { + colorFillClip(ptr_left, ptr_left + baseRight + bevel, bottom_color, ptr_x, ptr_y, _clippingArea); + + if (baseLeft) + colorFillClip(ptr_left - w - baseLeft + bevel, ptr_left - w + bevel + bevel, top_color, ptr_x - w - baseLeft + bevel, ptr_y, _clippingArea); + ptr_left += pitch; + ++ptr_y; + } +} + /** SQUARE ALGORITHM **/ template void VectorRendererSpec:: diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h index b69ab87bdd..7b2c2730df 100644 --- a/graphics/VectorRendererSpec.h +++ b/graphics/VectorRendererSpec.h @@ -60,7 +60,8 @@ public: void drawRoundedSquareClip(int x, int y, int r, int w, int h, int cx, int cy, int cw, int ch); void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient); void drawTriangleClip(int x, int y, int base, int height, TriangleOrientation orient, Common::Rect clipping); - void drawTab(int x, int y, int r, int w, int h); //TODO + void drawTab(int x, int y, int r, int w, int h); + void drawTabClip(int x, int y, int r, int w, int h, Common::Rect clipping); void drawBeveledSquare(int x, int y, int w, int h, int bevel) { drawBevelSquareAlg(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled); } @@ -223,12 +224,22 @@ protected: PixelType color, VectorRenderer::FillMode fill_m, int baseLeft = 0, int baseRight = 0); + virtual void drawTabAlgClip(int x, int y, int w, int h, int r, + PixelType color, VectorRenderer::FillMode fill_m, + int baseLeft = 0, int baseRight = 0); + virtual void drawTabShadow(int x, int y, int w, int h, int r); + virtual void drawTabShadowClip(int x, int y, int w, int h, int r); + virtual void drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType topColor, PixelType bottomColor, int baseLeft = 0, int baseRight = 0); + virtual void drawBevelTabAlgClip(int x, int y, int w, int h, + int bevel, PixelType topColor, PixelType bottomColor, + int baseLeft = 0, int baseRight = 0); + /** * SHADOW DRAWING ALGORITHMS * diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index 13bf8133ef..08245380a8 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -1351,6 +1351,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 &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; diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 3c83020f0e..d88890d39e 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -365,6 +365,9 @@ public: void drawTab(const Common::Rect &r, int tabHeight, int tabWidth, const Common::Array &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 &tabs, int active, uint16 hints, + int titleVPad, WidgetStateInfo state = kStateEnabled); void drawScrollbar(const Common::Rect &r, int sliderY, int sliderHeight, ScrollbarState, WidgetStateInfo state = kStateEnabled); diff --git a/gui/widgets/tab.cpp b/gui/widgets/tab.cpp index 393f63aac0..784e438952 100644 --- a/gui/widgets/tab.cpp +++ b/gui/widgets/tab.cpp @@ -308,9 +308,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+_tabHeight), _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() { -- cgit v1.2.3