aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2016-07-10 16:23:34 +0200
committerGitHub2016-07-10 16:23:34 +0200
commit9cec2eea5cdaf2893771f434c45648dcf7da88f2 (patch)
tree1882aab09f95ca00c9772a882e618aef2d6260cb
parent862f12c71b94346a8653d2eba5b6fc0a0d59a782 (diff)
parent846619fd42ecb11e94958e39bd61ea29a9ff76cd (diff)
downloadscummvm-rg350-9cec2eea5cdaf2893771f434c45648dcf7da88f2.tar.gz
scummvm-rg350-9cec2eea5cdaf2893771f434c45648dcf7da88f2.tar.bz2
scummvm-rg350-9cec2eea5cdaf2893771f434c45648dcf7da88f2.zip
Merge pull request #774 from Tkachov/the-container-box-pr2
GUI: Add ScrollContainerWidget
-rw-r--r--graphics/VectorRenderer.cpp29
-rw-r--r--graphics/VectorRenderer.h60
-rw-r--r--graphics/VectorRendererSpec.cpp1716
-rw-r--r--graphics/VectorRendererSpec.h73
-rw-r--r--graphics/nine_patch.cpp35
-rw-r--r--graphics/nine_patch.h1
-rw-r--r--graphics/transparent_surface.cpp133
-rw-r--r--graphics/transparent_surface.h8
-rw-r--r--gui/ThemeEngine.cpp455
-rw-r--r--gui/ThemeEngine.h31
-rw-r--r--gui/ThemeEval.cpp16
-rw-r--r--gui/ThemeLayout.h38
-rw-r--r--gui/dialog.cpp4
-rw-r--r--gui/gui-manager.cpp6
-rw-r--r--gui/gui-manager.h1
-rw-r--r--gui/module.mk1
-rw-r--r--gui/object.cpp13
-rw-r--r--gui/themes/scummmodern.zipbin1487883 -> 1491605 bytes
-rw-r--r--gui/themes/scummmodern/scummmodern_layout.stx2
-rw-r--r--gui/themes/scummmodern/scummmodern_layout_lowres.stx4
-rw-r--r--gui/widget.cpp51
-rw-r--r--gui/widget.h4
-rw-r--r--gui/widgets/editable.cpp4
-rw-r--r--gui/widgets/edittext.cpp4
-rw-r--r--gui/widgets/list.cpp8
-rw-r--r--gui/widgets/popup.cpp12
-rw-r--r--gui/widgets/scrollbar.cpp7
-rw-r--r--gui/widgets/scrollcontainer.cpp147
-rw-r--r--gui/widgets/scrollcontainer.h63
-rw-r--r--gui/widgets/tab.cpp16
30 files changed, 2861 insertions, 81 deletions
diff --git a/graphics/VectorRenderer.cpp b/graphics/VectorRenderer.cpp
index f426dd8c41..73dc6309b2 100644
--- a/graphics/VectorRenderer.cpp
+++ b/graphics/VectorRenderer.cpp
@@ -55,7 +55,34 @@ void VectorRenderer::drawStep(const Common::Rect &area, const DrawStep &step, ui
_dynamicData = extra;
- (this->*(step.drawingCall))(area, step);
+ Common::Rect noClip = Common::Rect(0, 0, 0, 0);
+ (this->*(step.drawingCall))(area, step, noClip);
+}
+
+void VectorRenderer::drawStepClip(const Common::Rect &area, const Common::Rect &clip, const DrawStep &step, uint32 extra) {
+
+ if (step.bgColor.set)
+ setBgColor(step.bgColor.r, step.bgColor.g, step.bgColor.b);
+
+ if (step.fgColor.set)
+ setFgColor(step.fgColor.r, step.fgColor.g, step.fgColor.b);
+
+ if (step.bevelColor.set)
+ setBevelColor(step.bevelColor.r, step.bevelColor.g, step.bevelColor.b);
+
+ if (step.gradColor1.set && step.gradColor2.set)
+ setGradientColors(step.gradColor1.r, step.gradColor1.g, step.gradColor1.b,
+ step.gradColor2.r, step.gradColor2.g, step.gradColor2.b);
+
+ setShadowOffset(_disableShadows ? 0 : step.shadow);
+ setBevel(step.bevel);
+ setGradientFactor(step.factor);
+ setStrokeWidth(step.stroke);
+ setFillMode((FillMode)step.fillMode);
+
+ _dynamicData = extra;
+
+ (this->*(step.drawingCall))(area, step, clip);
}
int VectorRenderer::stepGetRadius(const DrawStep &step, const Common::Rect &area) {
diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h
index 6b657f758d..0352808706 100644
--- a/graphics/VectorRenderer.h
+++ b/graphics/VectorRenderer.h
@@ -38,7 +38,7 @@ class VectorRenderer;
struct DrawStep;
-typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &);
+typedef void (VectorRenderer::*DrawingFunctionCallback)(const Common::Rect &, const Graphics::DrawStep &, const Common::Rect &);
struct DrawStep {
@@ -142,6 +142,7 @@ public:
* @param y2 Vertical (Y) coordinate for the line end
*/
virtual void drawLine(int x1, int y1, int x2, int y2) = 0;
+ virtual void drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) = 0;
/**
* Draws a circle centered at (x,y) with radius r.
@@ -151,6 +152,7 @@ public:
* @param r Radius of the circle.
*/
virtual void drawCircle(int x, int y, int r) = 0;
+ virtual void drawCircleClip(int x, int y, int r, Common::Rect clipping) = 0;
/**
* Draws a square starting at (x,y) with the given width and height.
@@ -161,6 +163,7 @@ public:
* @param h Height of the square
*/
virtual void drawSquare(int x, int y, int w, int h) = 0;
+ virtual void drawSquareClip(int x, int y, int w, int h, Common::Rect clipping) = 0;
/**
* Draws a rounded square starting at (x,y) with the given width and height.
@@ -173,6 +176,7 @@ public:
* @param r Radius of the corners.
*/
virtual void drawRoundedSquare(int x, int y, int r, int w, int h) = 0;
+ virtual void drawRoundedSquareClip(int x, int y, int r, int w, int h, Common::Rect clipping) = 0;
/**
* Draws a triangle starting at (x,y) with the given base and height.
@@ -186,6 +190,7 @@ public:
* @param orient Orientation of the triangle.
*/
virtual void drawTriangle(int x, int y, int base, int height, TriangleOrientation orient) = 0;
+ virtual void drawTriangleClip(int x, int y, int base, int height, TriangleOrientation orient, Common::Rect clipping) = 0;
/**
* Draws a beveled square like the ones in the Classic GUI themes.
@@ -199,6 +204,7 @@ public:
* @param bevel Amount of bevel. Must be positive.
*/
virtual void drawBeveledSquare(int x, int y, int w, int h, int bevel) = 0;
+ virtual void drawBeveledSquareClip(int x, int y, int w, int h, int bevel, Common::Rect clipping) = 0;
/**
* Draws a tab-like shape, specially thought for the Tab widget.
@@ -212,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;
/**
@@ -222,6 +229,11 @@ public:
drawLine(x + w, y, x, y + h);
}
+ virtual void drawCrossClip(int x, int y, int w, int h, Common::Rect clipping) {
+ drawLineClip(x, y, x + w, y + w, clipping);
+ drawLineClip(x + w, y, x, y + h, clipping);
+ }
+
/**
* Set the active foreground painting color for the renderer.
* All the foreground drawing from then on will be done with that color, unless
@@ -278,6 +290,7 @@ public:
* Defaults to using the active Foreground color for filling.
*/
virtual void fillSurface() = 0;
+ virtual void fillSurfaceClip(Common::Rect clipping) = 0;
/**
* Clears the active surface.
@@ -355,68 +368,68 @@ public:
/**
* DrawStep callback functions for each drawing feature
*/
- void drawCallback_CIRCLE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_CIRCLE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h, radius;
radius = stepGetRadius(step, area);
stepGetPositions(step, area, x, y, w, h);
- drawCircle(x + radius, y + radius, radius);
+ drawCircleClip(x + radius, y + radius, radius, clip);
}
- void drawCallback_SQUARE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_SQUARE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawSquare(x, y, w, h);
+ drawSquareClip(x, y, w, h, clip);
}
- void drawCallback_LINE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_LINE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawLine(x, y, x + w, y + w);
+ drawLineClip(x, y, x + w, y + w, clip);
}
- void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_ROUNDSQ(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawRoundedSquare(x, y, stepGetRadius(step, area), w, h);
+ drawRoundedSquareClip(x, y, stepGetRadius(step, area), w, h, clip);
}
- void drawCallback_FILLSURFACE(const Common::Rect &area, const DrawStep &step) {
- fillSurface();
+ void drawCallback_FILLSURFACE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
+ fillSurfaceClip(clip);
}
- void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_TRIANGLE(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawTriangle(x, y, w, h, (TriangleOrientation)step.extraData);
+ drawTriangleClip(x, y, w, h, (TriangleOrientation)step.extraData, clip);
}
- void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_BEVELSQ(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawBeveledSquare(x, y, w, h, _bevel);
+ drawBeveledSquareClip(x, y, w, h, _bevel, clip);
}
- void drawCallback_TAB(const Common::Rect &area, const DrawStep &step) {
+ 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) {
+ void drawCallback_BITMAP(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- blitAlphaBitmap(step.blitSrc, Common::Rect(x, y, x + w, y + h));
+ blitAlphaBitmapClip(step.blitSrc, Common::Rect(x, y, x + w, y + h), clip);
}
- void drawCallback_CROSS(const Common::Rect &area, const DrawStep &step) {
+ void drawCallback_CROSS(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {
uint16 x, y, w, h;
stepGetPositions(step, area, x, y, w, h);
- drawCross(x, y, w, h);
+ drawCrossClip(x, y, w, h, clip);
}
- void drawCallback_VOID(const Common::Rect &area, const DrawStep &step) {}
+ void drawCallback_VOID(const Common::Rect &area, const DrawStep &step, const Common::Rect &clip) {}
/**
* Draws the specified draw step on the screen.
@@ -426,6 +439,7 @@ public:
* @param step Pointer to a DrawStep struct.
*/
virtual void drawStep(const Common::Rect &area, const DrawStep &step, uint32 extra = 0);
+ virtual void drawStepClip(const Common::Rect &area, const Common::Rect &clip, const DrawStep &step, uint32 extra = 0);
/**
* Copies the part of the current frame to the system overlay.
@@ -466,8 +480,10 @@ public:
* blitted into the active surface, at the position specified by "r".
*/
virtual void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) = 0;
+ virtual void blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) = 0;
virtual void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) = 0;
+ virtual void blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) = 0;
/**
* Draws a string into the screen. Wrapper for the Graphics::Font string drawing
diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp
index 258d935440..b2314b0340 100644
--- a/graphics/VectorRendererSpec.cpp
+++ b/graphics/VectorRendererSpec.cpp
@@ -108,6 +108,33 @@ inline frac_t fp_sqroot(uint32 x) {
BE_DRAWCIRCLE_BOTTOM(ptr3,ptr4,x,y,px,py); \
} while (0)
+#define BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
+ if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
+ *(ptr1 + (y) - (px)) = color; \
+ if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
+ *(ptr1 + (x) - (py)) = color; \
+ if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
+ *(ptr2 - (x) - (py)) = color; \
+ if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
+ *(ptr2 - (y) - (px)) = color; \
+} while (0)
+
+#define BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
+ if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
+ *(ptr3 - (y) + (px)) = color; \
+ if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
+ *(ptr3 - (x) + (py)) = color; \
+ if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
+ *(ptr4 + (x) + (py)) = color; \
+ if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
+ *(ptr4 + (y) + (px)) = color; \
+} while (0)
+
+#define BE_DRAWCIRCLE_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
+ BE_DRAWCIRCLE_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
+ BE_DRAWCIRCLE_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR(ptr1,ptr2,ptr3,ptr4,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color1; \
*(ptr1 + (x) - (py)) = color1; \
@@ -119,6 +146,25 @@ inline frac_t fp_sqroot(uint32 x) {
*(ptr4 + (y) + (px)) = color2; \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
+ if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
+ *(ptr1 + (y) - (px)) = color1; \
+ if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
+ *(ptr1 + (x) - (py)) = color1; \
+ if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
+ *(ptr2 - (x) - (py)) = color1; \
+ if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
+ *(ptr2 - (y) - (px)) = color1; \
+ if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
+ *(ptr3 - (y) + (px)) = color1; \
+ if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
+ *(ptr3 - (x) + (py)) = color1; \
+ if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
+ *(ptr4 + (x) + (py)) = color2; \
+ if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
+ *(ptr4 + (y) + (px)) = color2; \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (y) - (px), color, a); \
} while (0)
@@ -127,6 +173,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr + (x) - (py), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (y), (realY) - (x))) \
+ this->blendPixelPtr(ptr + (y) - (px), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (x), (realY) - (y))) \
+ this->blendPixelPtr(ptr + (x) - (py), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (x) - (py), color, a); \
} while (0)
@@ -135,6 +191,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr - (y) - (px), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (x), (realY) - (y))) \
+ this->blendPixelPtr(ptr - (x) - (py), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (y), (realY) - (x))) \
+ this->blendPixelPtr(ptr - (y) - (px), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr - (y) + (px), color, a); \
} while (0)
@@ -143,6 +209,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr - (x) + (py), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (y), (realY) + (x))) \
+ this->blendPixelPtr(ptr - (y) + (px), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) - (x), (realY) + (y))) \
+ this->blendPixelPtr(ptr - (x) + (py), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \
this->blendPixelPtr(ptr + (x) + (py), color, a); \
} while (0)
@@ -151,6 +227,16 @@ inline frac_t fp_sqroot(uint32 x) {
this->blendPixelPtr(ptr + (y) + (px), color, a); \
} while (0)
+#define BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (x), (realY) + (y))) \
+ this->blendPixelPtr(ptr + (x) + (py), color, a); \
+} while (0)
+
+#define BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr,x,y,px,py,a,realX,realY) do { \
+ if (IS_IN_CLIP((realX) + (y), (realY) + (x))) \
+ this->blendPixelPtr(ptr + (y) + (px), color, a); \
+} while (0)
+
#define BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py) do { \
*(ptr1 + (y) - (px)) = color1; \
*(ptr1 + (x) - (py)) = color2; \
@@ -170,6 +256,42 @@ inline frac_t fp_sqroot(uint32 x) {
BE_DRAWCIRCLE_XCOLOR_BOTTOM(ptr3,ptr4,x,y,px,py); \
} while (0)
+#define IS_IN_CLIP(x,y) (_clippingArea.left <= (x) && (x) < _clippingArea.right \
+ && _clippingArea.top <= (y) && (y) < _clippingArea.bottom)
+
+#define BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2) do { \
+ if (IS_IN_CLIP((realX1) + (y), (realY1) - (x))) \
+ *(ptr1 + (y) - (px)) = color1; \
+\
+ if (IS_IN_CLIP((realX1) + (x), (realY1) - (y))) \
+ *(ptr1 + (x) - (py)) = color2; \
+\
+ if (IS_IN_CLIP((realX2) - (x), (realY2) - (y))) \
+ *(ptr2 - (x) - (py)) = color2; \
+\
+ if (IS_IN_CLIP((realX2) - (y), (realY2) - (x))) \
+ *(ptr2 - (y) - (px)) = color1; \
+} while (0)
+
+#define BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4) do { \
+ if (IS_IN_CLIP((realX3) - (y), (realY3) + (x))) \
+ *(ptr3 - (y) + (px)) = color3; \
+\
+ if (IS_IN_CLIP((realX3) - (x), (realY3) + (y))) \
+ *(ptr3 - (x) + (py)) = color4; \
+\
+ if (IS_IN_CLIP((realX4) + (x), (realY4) + (y))) \
+ *(ptr4 + (x) + (py)) = color4; \
+\
+ if (IS_IN_CLIP((realX4) + (y), (realY4) + (x))) \
+ *(ptr4 + (y) + (px)) = color3; \
+} while (0)
+
+#define BE_DRAWCIRCLE_XCOLOR_CLIP(ptr1,ptr2,ptr3,ptr4,x,y,px,py,realX1,realY1,realX2,realY2,realX3,realY3,realX4,realY4) do { \
+ BE_DRAWCIRCLE_XCOLOR_TOP_CLIP(ptr1,ptr2,x,y,px,py,realX1,realY1,realX2,realY2); \
+ BE_DRAWCIRCLE_XCOLOR_BOTTOM_CLIP(ptr3,ptr4,x,y,px,py,realX3,realY3,realX4,realY4); \
+} while (0)
+
#define BE_RESET() do { \
f = 1 - r; \
@@ -337,6 +459,45 @@ void colorFill(PixelType *first, PixelType *last, PixelType color) {
}
}
+template<typename PixelType>
+void colorFillClip(PixelType *first, PixelType *last, PixelType color, int realX, int realY, Common::Rect &clippingArea) {
+ if (realY < clippingArea.top || realY >= clippingArea.bottom)
+ return;
+
+ register int count = (last - first);
+
+ if (realX > clippingArea.right || realX + count < clippingArea.left)
+ return;
+
+ if (realX < clippingArea.left) {
+ register int diff = (clippingArea.left - realX);
+ realX += diff;
+ count -= diff;
+ }
+
+ if (clippingArea.right <= realX + count) {
+ register int diff = (realX + count - clippingArea.right);
+ count -= diff;
+ }
+
+ if (!count)
+ return;
+
+ register int n = (count + 7) >> 3;
+ switch (count % 8) {
+ case 0: do {
+ *first++ = color;
+ case 7: *first++ = color;
+ case 6: *first++ = color;
+ case 5: *first++ = color;
+ case 4: *first++ = color;
+ case 3: *first++ = color;
+ case 2: *first++ = color;
+ case 1: *first++ = color;
+ } while (--n > 0);
+ }
+}
+
VectorRenderer *createRenderer(int mode) {
#ifdef DISABLE_FANCY_THEMES
@@ -376,6 +537,7 @@ VectorRendererSpec(PixelFormat format) :
_alphaMask((0xFF >> format.aLoss) << format.aShift) {
_bitmapAlphaColor = _format.RGBToColor(255, 0, 255);
+ _clippingArea = Common::Rect(0, 0, 32767, 32767);
}
/****************************
@@ -480,6 +642,49 @@ gradientFill(PixelType *ptr, int width, int x, int y) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+gradientFillClip(PixelType *ptr, int width, int x, int y, int realX, int realY) {
+ if (realY < _clippingArea.top || realY >= _clippingArea.bottom) return;
+ bool ox = ((y & 1) == 1);
+ int curGrad = 0;
+
+ while (_gradIndexes[curGrad + 1] <= y)
+ curGrad++;
+
+ // precalcGradient assures that _gradIndexes entries always differ in
+ // their value. This assures stripSize is always different from zero.
+ int stripSize = _gradIndexes[curGrad + 1] - _gradIndexes[curGrad];
+
+ int grad = (((y - _gradIndexes[curGrad]) % stripSize) << 2) / stripSize;
+
+ // Dithering:
+ // +--+ +--+ +--+ +--+
+ // | | | | | *| | *|
+ // | | | *| |* | |**|
+ // +--+ +--+ +--+ +--+
+ // 0 1 2 3
+ if (grad == 0 ||
+ _gradCache[curGrad] == _gradCache[curGrad + 1] || // no color change
+ stripSize < 2) { // the stip is small
+ colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad]);
+ } else if (grad == 3 && ox) {
+ colorFill<PixelType>(ptr, ptr + width, _gradCache[curGrad + 1]);
+ } else {
+ for (int j = x; j < x + width; j++, ptr++) {
+ if (realX + j - x < _clippingArea.left || realX + j - x >= _clippingArea.right) continue;
+ bool oy = ((j & 1) == 1);
+
+ if ((ox && oy) ||
+ ((grad == 2 || grad == 3) && ox && !oy) ||
+ (grad == 3 && oy))
+ *ptr = _gradCache[curGrad + 1];
+ else
+ *ptr = _gradCache[curGrad];
+ }
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
fillSurface() {
byte *ptr = (byte *)_activeSurface->getPixels();
@@ -503,6 +708,44 @@ fillSurface() {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+fillSurfaceClip(Common::Rect clipping) {
+ int w = _activeSurface->w;
+ int h = _activeSurface->h;
+ if (clipping.isEmpty() || (clipping.left == 0 && clipping.top == 0 && clipping.right == w && clipping.bottom == h)) {
+ fillSurface();
+ return;
+ }
+
+ byte *ptr = (byte *)_activeSurface->getPixels();
+ int pitch = _activeSurface->pitch;
+
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillForeground) {
+ PixelType color = (Base::_fillMode == kFillBackground ? _bgColor : _fgColor);
+ byte *ptrLeft = (ptr + _clippingArea.left), *ptrRight = ptr + _clippingArea.right;
+ for (int i = 0; i < h; i++) {
+ if (_clippingArea.top <= i && i < _clippingArea.bottom) {
+ colorFill<PixelType>((PixelType *)ptrLeft, (PixelType *)ptrRight, color);
+ }
+
+ ptrLeft += pitch;
+ ptrRight += pitch;
+ }
+
+ } else if (Base::_fillMode == kFillGradient) {
+ precalcGradient(h);
+
+ for (int i = 0; i < h; i++) {
+ if (_clippingArea.top <= i && i < _clippingArea.bottom) {
+ gradientFill((PixelType *)ptr + _clippingArea.left, _clippingArea.width(), 0, i);
+ }
+
+ ptr += pitch;
+ }
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
copyFrame(OSystem *sys, const Common::Rect &r) {
sys->copyRectToOverlay(
@@ -554,6 +797,58 @@ blitSubSurface(const Graphics::Surface *source, const Common::Rect &r) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) {
+ if (clipping.isEmpty() || clipping.contains(r)) {
+ blitSubSurface(source, r);
+ return;
+ }
+
+ int16 x = r.left;
+ int16 y = r.top;
+
+ if (r.width() > source->w)
+ x = x + (r.width() >> 1) - (source->w >> 1);
+
+ if (r.height() > source->h)
+ y = y + (r.height() >> 1) - (source->h >> 1);
+
+ int w = source->w, h = source->h;
+ int usedW = w, usedH = h;
+ int offsetX = 0, offsetY = 0;
+
+ if (x > clipping.right || x + w < clipping.left) return;
+ if (y > clipping.bottom || y + h < clipping.top) return;
+ if (x < clipping.left) {
+ offsetX = clipping.left - x;
+ usedW -= offsetX;
+ x = clipping.left;
+ }
+ if (y < clipping.top) {
+ offsetY = clipping.top - y;
+ usedH -= offsetY;
+ y = clipping.top;
+ }
+ if (usedW > clipping.width()) usedW = clipping.width();
+ if (usedH > clipping.width()) usedH = clipping.height();
+
+ byte *dst_ptr = (byte *)_activeSurface->getBasePtr(x, y);
+ const byte *src_ptr = (const byte *)source->getBasePtr(offsetX, offsetY);
+
+ const int dst_pitch = _activeSurface->pitch;
+ const int src_pitch = source->pitch;
+
+ int lines = usedH;
+ const int sz = usedW * sizeof(PixelType);
+
+ while (lines--) {
+ memcpy(dst_ptr, src_ptr, sz);
+ dst_ptr += dst_pitch;
+ src_ptr += src_pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) {
int16 x = r.left;
int16 y = r.top;
@@ -590,6 +885,65 @@ blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping) {
+ if (clipping.isEmpty() || clipping.contains(r)) {
+ blitAlphaBitmap(source, r);
+ return;
+ }
+
+ int16 x = r.left;
+ int16 y = r.top;
+
+ if (r.width() > source->w)
+ x = x + (r.width() >> 1) - (source->w >> 1);
+
+ if (r.height() > source->h)
+ y = y + (r.height() >> 1) - (source->h >> 1);
+
+ int w = source->w, h = source->h;
+ int usedW = w, usedH = h;
+ int offsetX = 0, offsetY = 0;
+
+ if (x > clipping.right || x + w < clipping.left) return;
+ if (y > clipping.bottom || y + h < clipping.top) return;
+ if (x < clipping.left) {
+ offsetX = clipping.left - x;
+ usedW -= offsetX;
+ x = clipping.left;
+ }
+ if (y < clipping.top) {
+ offsetY = clipping.top - y;
+ usedH -= offsetY;
+ y = clipping.top;
+ }
+ if (usedW > clipping.width()) usedW = clipping.width();
+ if (usedH > clipping.width()) usedH = clipping.height();
+
+ PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ const PixelType *src_ptr = (const PixelType *)source->getBasePtr(offsetX, offsetY);
+
+ int dst_pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int src_pitch = source->pitch / source->format.bytesPerPixel;
+
+ h = usedH;
+ while (h--) {
+ w = usedW;
+
+ while (w--) {
+ if (*src_ptr != _bitmapAlphaColor)
+ *dst_ptr = *src_ptr;
+
+ dst_ptr++;
+ src_ptr++;
+ }
+
+ dst_ptr = dst_ptr - usedW + dst_pitch;
+ src_ptr = src_ptr - usedW + src_pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle) {
int pixels = _activeSurface->w * _activeSurface->h;
PixelType *ptr = (PixelType *)_activeSurface->getPixels();
@@ -667,6 +1021,13 @@ blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha) {
template<typename PixelType>
inline void VectorRendererSpec<PixelType>::
+blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y) {
+ if (IS_IN_CLIP(x, y))
+ blendPixelPtr(ptr, color, alpha);
+}
+
+template<typename PixelType>
+inline void VectorRendererSpec<PixelType>::
blendPixelDestAlphaPtr(PixelType *ptr, PixelType color, uint8 alpha) {
int idst = *ptr;
// This function is only used for corner pixels in rounded rectangles, so
@@ -710,6 +1071,36 @@ darkenFill(PixelType *ptr, PixelType *end) {
}
}
+template<typename PixelType>
+inline void VectorRendererSpec<PixelType>::
+darkenFillClip(PixelType *ptr, PixelType *end, int x, int y) {
+ PixelType mask = (PixelType)((3 << _format.rShift) | (3 << _format.gShift) | (3 << _format.bShift));
+
+ if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) {
+ // !kFeatureOverlaySupportsAlpha (but might have alpha bits)
+
+ while (ptr != end) {
+ if (IS_IN_CLIP(x, y)) *ptr = ((*ptr & ~mask) >> 2) | _alphaMask;
+ ++ptr;
+ ++x;
+ }
+ } else {
+ // kFeatureOverlaySupportsAlpha
+ // assuming at least 3 alpha bits
+
+ mask |= 3 << _format.aShift;
+ PixelType addA = (PixelType)(3 << (_format.aShift + 6 - _format.aLoss));
+
+ while (ptr != end) {
+ // Darken the color, and increase the alpha
+ // (0% -> 75%, 100% -> 100%)
+ if (IS_IN_CLIP(x, y)) *ptr = (PixelType)(((*ptr & ~mask) >> 2) + addA);
+ ++ptr;
+ ++x;
+ }
+ }
+}
+
/********************************************************************
********************************************************************
* Primitive shapes drawing - Public API calls - VectorRendererSpec *
@@ -818,6 +1209,77 @@ drawLine(int x1, int y1, int x2, int y2) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping) {
+ x1 = CLIP(x1, 0, (int)Base::_activeSurface->w);
+ x2 = CLIP(x2, 0, (int)Base::_activeSurface->w);
+ y1 = CLIP(y1, 0, (int)Base::_activeSurface->h);
+ y2 = CLIP(y2, 0, (int)Base::_activeSurface->h);
+
+ // we draw from top to bottom
+ if (y2 < y1) {
+ SWAP(x1, x2);
+ SWAP(y1, y2);
+ }
+
+ uint dx = ABS(x2 - x1);
+ uint dy = ABS(y2 - y1);
+
+ // this is a point, not a line. stoopid.
+ if (dy == 0 && dx == 0)
+ return;
+
+ if (Base::_strokeWidth == 0)
+ return;
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int st = Base::_strokeWidth >> 1;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool needsClipping = !_clippingArea.isEmpty() && (!_clippingArea.contains(x1, y1) || !_clippingArea.contains(x2, y2));
+ if (!needsClipping) {
+ drawLine(x1, y1, x2, y2);
+ _clippingArea = backup;
+ return;
+ }
+
+ int ptr_x = x1, ptr_y = y1;
+
+ if (dy == 0) { // horizontal lines
+ colorFillClip<PixelType>(ptr, ptr + dx + 1, (PixelType)_fgColor, x1, y1, _clippingArea);
+
+ for (int i = 0, p = pitch; i < st; ++i, p += pitch) {
+ colorFillClip<PixelType>(ptr + p, ptr + dx + 1 + p, (PixelType)_fgColor, x1, y1 + p/pitch, _clippingArea);
+ colorFillClip<PixelType>(ptr - p, ptr + dx + 1 - p, (PixelType)_fgColor, x1, y1 - p/pitch, _clippingArea);
+ }
+
+ } else if (dx == 0) { // vertical lines
+ // these ones use a static pitch increase.
+ while (y1++ <= y2) {
+ colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, x1 - st, ptr_y, _clippingArea);
+ ptr += pitch;
+ ++ptr_y;
+ }
+
+ } else if (dx == dy) { // diagonal lines
+ // these ones also use a fixed pitch increase
+ pitch += (x2 > x1) ? 1 : -1;
+
+ while (dy--) {
+ colorFillClip<PixelType>(ptr - st, ptr + st, (PixelType)_fgColor, ptr_x - st, ptr_y, _clippingArea);
+ ptr += pitch;
+ ++ptr_y;
+ if (x2 > x1) ++ptr_x; else --ptr_x;
+ }
+
+ } else { // generic lines, use the standard algorithm...
+ drawLineAlgClip(x1, y1, x2, y2, dx, dy, (PixelType)_fgColor);
+ }
+}
+
/** CIRCLES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -857,6 +1319,70 @@ drawCircle(int x, int y, int r) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawCircleClip(int x, int y, int r, Common::Rect clipping) {
+ if (x + r > Base::_activeSurface->w || y + r > Base::_activeSurface->h ||
+ x - r < 0 || y - r < 0 || x == 0 || y == 0 || r <= 0)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x - r, y - r, x + r, y + r)));
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + r + Base::_shadowOffset < Base::_activeSurface->w
+ && y + r + Base::_shadowOffset < Base::_activeSurface->h) {
+ if (useClippingVersions)
+ drawCircleAlgClip(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
+ else
+ drawCircleAlg(x + Base::_shadowOffset + 1, y + Base::_shadowOffset + 1, r, 0, kFillForeground);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth) {
+ if (useClippingVersions)
+ drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
+ else
+ drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillForeground:
+ if (useClippingVersions)
+ drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
+ else
+ drawCircleAlg(x, y, r, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ if (Base::_strokeWidth > 1) {
+ if (useClippingVersions) {
+ drawCircleAlgClip(x, y, r, _fgColor, kFillForeground);
+ drawCircleAlgClip(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
+ } else {
+ drawCircleAlg(x, y, r, _fgColor, kFillForeground);
+ drawCircleAlg(x, y, r - Base::_strokeWidth, _bgColor, kFillBackground);
+ }
+ } else {
+ if (useClippingVersions) {
+ drawCircleAlgClip(x, y, r, _bgColor, kFillBackground);
+ drawCircleAlgClip(x, y, r, _fgColor, kFillDisabled);
+ } else {
+ drawCircleAlg(x, y, r, _bgColor, kFillBackground);
+ drawCircleAlg(x, y, r, _fgColor, kFillDisabled);
+ }
+ }
+ break;
+
+ case kFillGradient:
+ break;
+ }
+
+ _clippingArea = backup;
+}
+
/** SQUARES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -894,6 +1420,67 @@ drawSquare(int x, int y, int w, int h) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawSquareClip(int x, int y, 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)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + w + Base::_shadowOffset < Base::_activeSurface->w
+ && y + h + Base::_shadowOffset < Base::_activeSurface->h) {
+ if (useClippingVersions)
+ drawSquareShadowClip(x, y, w, h, Base::_shadowOffset);
+ else
+ drawSquareShadow(x, y, w, h, Base::_shadowOffset);
+ }
+
+ switch (Base::_fillMode) {
+ case kFillDisabled:
+ if (Base::_strokeWidth) {
+ if (useClippingVersions)
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
+ else
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillForeground:
+ if (useClippingVersions)
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillForeground);
+ else
+ drawSquareAlg(x, y, w, h, _fgColor, kFillForeground);
+ break;
+
+ case kFillBackground:
+ if (useClippingVersions) {
+ drawSquareAlgClip(x, y, w, h, _bgColor, kFillBackground);
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
+ } else {
+ drawSquareAlg(x, y, w, h, _bgColor, kFillBackground);
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+
+ case kFillGradient:
+ VectorRendererSpec::drawSquareAlg(x, y, w, h, 0, kFillGradient);
+ if (Base::_strokeWidth) {
+ if (useClippingVersions)
+ drawSquareAlgClip(x, y, w, h, _fgColor, kFillDisabled);
+ else
+ drawSquareAlg(x, y, w, h, _fgColor, kFillDisabled);
+ }
+ break;
+ }
+
+ _clippingArea = backup;
+}
+
/** ROUNDED SQUARES **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -920,6 +1507,43 @@ drawRoundedSquare(int x, int y, int r, int w, int h) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawRoundedSquareClip(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 <= 0)
+ return;
+
+ if ((r * 2) > w || (r * 2) > h)
+ r = MIN(w / 2, h / 2);
+
+ if (r <= 0)
+ return;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useOriginal = (_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (Base::_fillMode != kFillDisabled && Base::_shadowOffset
+ && x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w
+ && y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h
+ && h > (Base::_shadowOffset + 1) * 2) {
+ if (useOriginal) {
+ drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset);
+ } else {
+ drawRoundedSquareShadowClip(x, y, r, w, h, Base::_shadowOffset);
+ }
+ }
+
+ if (useOriginal) {
+ drawRoundedSquareAlg(x, y, r, w, h, _fgColor, Base::_fillMode);
+ } else {
+ drawRoundedSquareAlgClip(x, y, r, w, h, _fgColor, Base::_fillMode);
+ }
+
+ _clippingArea = backup;
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawTab(int x, int y, int r, int w, int h) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h ||
w <= 0 || h <= 0 || x < 0 || y < 0 || r > w || r > h)
@@ -956,6 +1580,66 @@ drawTab(int x, int y, int r, int w, int h) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+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<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
@@ -1022,8 +1706,88 @@ drawTriangle(int x, int y, int w, int h, TriangleOrientation orient) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawTriangleClip(int x, int y, int w, int h, TriangleOrientation orient, Common::Rect clipping) {
+ if (x + w > Base::_activeSurface->w || y + h > Base::_activeSurface->h)
+ return;
+ PixelType color = 0;
+ if (Base::_strokeWidth <= 1) {
+ if (Base::_fillMode == kFillForeground)
+ color = _fgColor;
+ else if (Base::_fillMode == kFillBackground)
+ color = _bgColor;
+ } else {
+ if (Base::_fillMode == kFillDisabled)
+ return;
+ color = _fgColor;
+ }
+
+ if (Base::_dynamicData != 0)
+ orient = (TriangleOrientation)Base::_dynamicData;
+
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ bool useClippingVersions = !(_clippingArea.isEmpty() || _clippingArea.contains(Common::Rect(x, y, x + w, y + h)));
+
+ if (w == h) {
+ int newW = w;
+
+ switch (orient) {
+ case kTriangleUp:
+ case kTriangleDown:
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ else
+ drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ break;
+
+ case kTriangleLeft:
+ case kTriangleRight:
+ case kTriangleAuto:
+ break;
+ }
+
+ if (Base::_strokeWidth > 0)
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ else
+ drawTriangleVertAlg(x, y, newW, newW, (orient == kTriangleDown), color, Base::_fillMode);
+ }
+ } else {
+ int newW = w;
+ int newH = h;
+
+ switch (orient) {
+ case kTriangleUp:
+ case kTriangleDown:
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
+ else
+ drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), color, Base::_fillMode);
+ break;
+
+ case kTriangleLeft:
+ case kTriangleRight:
+ case kTriangleAuto:
+ break;
+ }
+
+ if (Base::_strokeWidth > 0) {
+ if (Base::_fillMode == kFillBackground || Base::_fillMode == kFillGradient) {
+ if (useClippingVersions)
+ drawTriangleVertAlgClip(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
+ else
+ drawTriangleVertAlg(x, y, newW, newH, (orient == kTriangleDown), _fgColor, kFillDisabled);
+ }
+ }
+ }
+
+ _clippingArea = backup;
+}
/********************************************************************
@@ -1134,6 +1898,120 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer:
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+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<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, fill_x + r, fill_y + sp/pitch, _clippingArea);
+ colorFillClip<PixelType>(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<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color, fill_x, fill_y, _clippingArea);
+ colorFillClip<PixelType>(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<PixelType>(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<PixelType>(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<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color, tl_x - x, tl_y - y, _clippingArea);
+ colorFillClip<PixelType>(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<PixelType>(ptr_fill, ptr_fill + w + 1, color, fill_x, fill_y, _clippingArea);
+ }
+ ptr_fill += pitch;
+ ++fill_y;
+ }
+ }
+}
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1196,6 +2074,72 @@ drawTabShadow(int x1, int y1, int w, int h, int r) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+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<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1240,6 +2184,57 @@ drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType top_color, Pixe
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+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<PixelType>(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<PixelType>(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<PixelType>(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<PixelType>(ptr_left, ptr_left + baseRight + bevel, bottom_color, ptr_x, ptr_y, _clippingArea);
+
+ if (baseLeft)
+ colorFillClip<PixelType>(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<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1278,6 +2273,46 @@ drawSquareAlg(int x, int y, int w, int h, PixelType color, VectorRenderer::FillM
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawSquareAlgClip(int x, int y, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Do not draw anything for empty rects.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int max_h = h;
+ int ptr_y = y;
+
+ if (fill_m != kFillDisabled) {
+ while (h--) {
+ if (fill_m == kFillGradient)
+ color = calcGradient(max_h - h, max_h);
+
+ colorFillClip<PixelType>(ptr, ptr + w, color, x, ptr_y, _clippingArea);
+ ptr += pitch;
+ ++ptr_y;
+ }
+ } else {
+ int sw = Base::_strokeWidth, sp = 0, hp = pitch * (h - 1);
+
+ while (sw--) {
+ colorFillClip<PixelType>(ptr + sp, ptr + w + sp, color, x, ptr_y + sp/pitch, _clippingArea);
+ colorFillClip<PixelType>(ptr + hp - sp, ptr + w + hp - sp, color, x, ptr_y + h - sp/pitch, _clippingArea);
+ sp += pitch;
+ }
+
+ while (h--) {
+ colorFillClip<PixelType>(ptr, ptr + Base::_strokeWidth, color, x, ptr_y, _clippingArea);
+ colorFillClip<PixelType>(ptr + w - Base::_strokeWidth, ptr + w, color, x + w - Base::_strokeWidth, ptr_y, _clippingArea);
+ ptr += pitch;
+ ptr_y += 1;
+ }
+ }
+}
+
/** SQUARE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1334,6 +2369,72 @@ drawBevelSquareAlg(int x, int y, int w, int h, int bevel, PixelType top_color, P
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawBevelSquareAlgClip(int x, int y, int w, int h, int bevel, PixelType top_color, PixelType bottom_color, bool fill) {
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int i, j;
+ PixelType *ptr_left;
+ int ptr_x, ptr_y;
+
+ // Fill Background
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ ptr_x = x; ptr_y = y;
+ i = h;
+ if (fill) {
+ assert((_bgColor & ~_alphaMask) == 0); // only support black
+ while (i--) {
+ darkenFillClip(ptr_left, ptr_left + w, ptr_x, ptr_y);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+ }
+
+ x = MAX(x - bevel, 0);
+ y = MAX(y - bevel, 0);
+
+ w = MIN(w + (bevel * 2), (int)_activeSurface->w);
+ h = MIN(h + (bevel * 2), (int)_activeSurface->h);
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y);
+ ptr_x = x; ptr_y = y;
+ i = bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + w, top_color, ptr_x, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + bevel);
+ ptr_x = x; ptr_y = y + bevel;
+ i = h - bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left, ptr_left + bevel, top_color, ptr_x, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x, y + h - bevel);
+ ptr_x = x; ptr_y = y + h - bevel;
+ i = bevel;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left + i, ptr_left + w, bottom_color, ptr_x + i, ptr_y, _clippingArea);
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+
+ ptr_left = (PixelType *)_activeSurface->getBasePtr(x + w - bevel, y);
+ ptr_x = x + w - bevel; ptr_y = y;
+ i = h - bevel;
+ j = bevel - 1;
+ while (i--) {
+ colorFillClip<PixelType>(ptr_left + j, ptr_left + bevel, bottom_color, ptr_x + j, ptr_y, _clippingArea);
+ if (j > 0) j--;
+ ptr_left += pitch;
+ ++ptr_y;
+ }
+}
+
/** GENERIC LINE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1382,6 +2483,59 @@ drawLineAlg(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
*ptr = (PixelType)color;
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawLineAlgClip(int x1, int y1, int x2, int y2, uint dx, uint dy, PixelType color) {
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int xdir = (x2 > x1) ? 1 : -1;
+ int ptr_x = x1, ptr_y = y1;
+
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+
+ if (dx > dy) {
+ int ddy = dy * 2;
+ int dysub = ddy - (dx * 2);
+ int error_term = ddy - dx;
+
+ while (dx--) {
+ if (error_term >= 0) {
+ ptr += pitch;
+ ++ptr_y;
+ error_term += dysub;
+ } else {
+ error_term += ddy;
+ }
+
+ ptr += xdir;
+ ptr_x += xdir;
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+ }
+ } else {
+ int ddx = dx * 2;
+ int dxsub = ddx - (dy * 2);
+ int error_term = ddx - dy;
+
+ while (dy--) {
+ if (error_term >= 0) {
+ ptr += xdir;
+ ptr_x += xdir;
+ error_term += dxsub;
+ } else {
+ error_term += ddx;
+ }
+
+ ptr += pitch;
+ ++ptr_y;
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+ }
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x2, y2);
+ ptr_x = x2; ptr_y = y2;
+ if (IS_IN_CLIP(ptr_x, ptr_y)) *ptr = (PixelType)color;
+}
+
/** VERTICAL TRIANGLE DRAWING ALGORITHM **/
/**
FIXED POINT ARITHMETIC
@@ -1580,6 +2734,212 @@ drawTriangleVertAlg(int x1, int y1, int w, int h, bool inverted, PixelType color
}
+/////////////
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawTriangleVertAlgClip(int x1, int y1, int w, int h, bool inverted, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Don't draw anything for empty rects. This assures dy is always different
+ // from zero.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int gradient_h = 0;
+ int y_pitch_sign = 1;
+ if (!inverted) {
+ pitch = -pitch;
+ y1 += h;
+ y_pitch_sign = -1;
+ }
+
+ PixelType *ptr_right = (PixelType *)_activeSurface->getBasePtr(x1, y1);
+ PixelType *floor = ptr_right - 1;
+ PixelType *ptr_left = (PixelType *)_activeSurface->getBasePtr(x1 + w, y1);
+
+ int x2 = x1 + w / 2;
+ int y2 = y1 + h;
+ int x_right = x1;
+ int y_right = y1;
+ int x_left = x1 + w;
+ int y_left = y1;
+ int x_floor = x_right - 1;
+ int y_floor = y_right;
+
+#if FIXED_POINT
+ int dx = (x2 - x1) << 8;
+ int dy = (y2 - y1) << 8;
+
+ if (abs(dx) > abs(dy)) {
+#else
+ double dx = (double)x2 - (double)x1;
+ double dy = (double)y2 - (double)y1;
+
+ if (fabs(dx) > fabs(dy)) {
+#endif
+ while (floor++ != ptr_left)
+ blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
+
+#if FIXED_POINT
+ // In this branch dx is always different from zero. This is because
+ // abs(dx) is strictly greater than abs(dy), and abs returns zero
+ // as minimal value.
+ int gradient = (dy << 8) / dx;
+ int intery = (y1 << 8) + gradient;
+#else
+ double gradient = dy / dx;
+ double intery = y1 + gradient;
+#endif
+
+ for (int x = x1 + 1; x < x2; x++) {
+#if FIXED_POINT
+ if (intery + gradient > ipart(intery) + 0x100) {
+#else
+ if (intery + gradient > ipart(intery) + 1) {
+#endif
+ ptr_right++;
+ ptr_left--;
+ ++x_right;
+ --x_left;
+ }
+
+ ptr_left += pitch;
+ ptr_right += pitch;
+ y_right += y_pitch_sign;
+ y_left += y_pitch_sign;
+
+ intery += gradient;
+
+ switch (fill_m) {
+ case kFillDisabled:
+ if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
+ if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
+ break;
+ case kFillForeground:
+ case kFillBackground:
+ colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
+ break;
+ case kFillGradient:
+ colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(intery), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(intery), x_left, y_left);
+ break;
+ }
+ }
+
+ return;
+ }
+
+#if FIXED_POINT
+ if (abs(dx) < abs(dy)) {
+#else
+ if (fabs(dx) < fabs(dy)) {
+#endif
+ ptr_left--;
+ --x_left;
+ while (floor++ != ptr_left)
+ blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
+
+#if FIXED_POINT
+ int gradient = (dx << 8) / (dy + 0x100);
+ int interx = (x1 << 8) + gradient;
+#else
+ double gradient = dx / (dy + 1);
+ double interx = x1 + gradient;
+#endif
+
+ for (int y = y1 + 1; y < y2; y++) {
+#if FIXED_POINT
+ if (interx + gradient > ipart(interx) + 0x100) {
+#else
+ if (interx + gradient > ipart(interx) + 1) {
+#endif
+ ptr_right++;
+ ptr_left--;
+ ++x_right;
+ --x_left;
+ }
+
+ ptr_left += pitch;
+ ptr_right += pitch;
+ y_right += y_pitch_sign;
+ y_left += y_pitch_sign;
+
+ interx += gradient;
+
+ switch (fill_m) {
+ case kFillDisabled:
+ if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
+ if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
+ break;
+ case kFillForeground:
+ case kFillBackground:
+ colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ case kFillGradient:
+ colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ }
+ }
+
+ return;
+ }
+
+ ptr_left--;
+ --x_left;
+ while (floor++ != ptr_left)
+ blendPixelPtrClip(floor, color, 50, ++x_floor, y_floor);
+
+#if FIXED_POINT
+ int gradient = (dx / dy) << 8;
+ int interx = (x1 << 8) + gradient;
+#else
+ double gradient = dx / dy;
+ double interx = x1 + gradient;
+#endif
+
+ for (int y = y1 + 1; y < y2; y++) {
+ ptr_right++;
+ ptr_left--;
+ ++x_right;
+ --x_left;
+
+ ptr_left += pitch;
+ ptr_right += pitch;
+ y_right += y_pitch_sign;
+ y_left += y_pitch_sign;
+
+ interx += gradient;
+
+ switch (fill_m) {
+ case kFillDisabled:
+ if (IS_IN_CLIP(x_left, y_left)) *ptr_left = color;
+ if (IS_IN_CLIP(x_right, y_right)) *ptr_right = color;
+ break;
+ case kFillForeground:
+ case kFillBackground:
+ colorFillClip<PixelType>(ptr_right + 1, ptr_left, color, x_right+1, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ case kFillGradient:
+ colorFillClip<PixelType>(ptr_right, ptr_left, calcGradient(gradient_h++, h), x_right, y_right, _clippingArea);
+ blendPixelPtrClip(ptr_right, color, rfpart(interx), x_right, y_right);
+ blendPixelPtrClip(ptr_left, color, rfpart(interx), x_left, y_left);
+ break;
+ }
+ }
+}
+
+/////////////
+
/** VERTICAL TRIANGLE DRAWING - FAST VERSION FOR SQUARED TRIANGLES */
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1682,6 +3042,9 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
while (x++ < (y - 2)) {
BE_ALGORITHM();
+ if (x < _clippingArea.left || x > _clippingArea.right) continue;
+ if (y < _clippingArea.top || y > _clippingArea.bottom) continue;
+
BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)));
BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)));
BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)));
@@ -1709,6 +3072,74 @@ drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color,
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int sw = 0, sp = 0, hp = h * pitch;
+
+ 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_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int real_radius = r;
+ int short_h = h - (2 * r) + 2;
+
+ PixelType color1 = color;
+ PixelType color2 = color;
+
+ while (sw++ < Base::_strokeWidth) {
+ blendFillClip(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t,
+ x1 + r, y1 + sp/pitch); // top
+ blendFillClip(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b,
+ x1 + r, y1 + (hp - sp)/ pitch); // bottom
+ sp += pitch;
+
+ BE_RESET();
+ r--;
+
+ int alphaStep_tr = ((alpha_t - alpha_r) / (y + 1));
+ int alphaStep_br = ((alpha_r - alpha_b) / (y + 1));
+ int alphaStep_bl = ((alpha_b - alpha_l) / (y + 1));
+ int alphaStep_tl = ((alpha_l - alpha_t) / (y + 1));
+
+ // Avoid blending the last pixels twice, since we have an alpha
+ while (x++ < (y - 2)) {
+ BE_ALGORITHM();
+
+ BE_DRAWCIRCLE_BCOLOR_TR_CW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x)), x1 + w - r, y1 + r);
+ BE_DRAWCIRCLE_BCOLOR_BR_CW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x)), x1 + w - r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_BL_CW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x)), x1 + r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_TL_CW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x)), x1 + r, y1 + r);
+
+ BE_DRAWCIRCLE_BCOLOR_TR_CCW_CLIP(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x)), x1 + w - r, y1 + r);
+ BE_DRAWCIRCLE_BCOLOR_BR_CCW_CLIP(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x)), x1 + w - r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_BL_CCW_CLIP(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x)), x1 + r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_TL_CCW_CLIP(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x)), x1 + r, y1 + r);
+
+ if (Base::_strokeWidth > 1) {
+ BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ BE_DRAWCIRCLE_BCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ }
+ }
+ }
+
+ ptr_fill += pitch * real_radius;
+ while (short_h--) {
+ blendFillClip(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l,
+ x1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // left
+ blendFillClip(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r,
+ x1 + w - Base::_strokeWidth + 1, y1 + real_radius + h - (2 * r) + 2 - short_h - 1); // right
+ ptr_fill += pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
// Do not draw empty space rounded squares.
if (w <= 0 || h <= 0) {
@@ -1740,6 +3171,8 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
while (x++ < y) {
BE_ALGORITHM();
+ if (y1 + r + y < _clippingArea.top || y1 + r + y > _clippingArea.bottom) continue;
+
color1 = calcGradient(real_radius - x, long_h);
color2 = calcGradient(real_radius - y, long_h);
color3 = calcGradient(long_h - r + x, long_h);
@@ -1781,6 +3214,91 @@ drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType colo
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ // Do not draw empty space rounded squares.
+ if (w <= 0 || h <= 0) {
+ return;
+ }
+
+ int f, ddF_x, ddF_y;
+ int x, y, px, py;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+
+ 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_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ int real_radius = r;
+ int short_h = h - (2 * r) + 2;
+ int long_h = h;
+
+ BE_RESET();
+
+ PixelType color1 = color;
+
+ if (fill_m == kFillGradient) {
+ PixelType color2, color3, color4;
+ precalcGradient(long_h);
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ color1 = calcGradient(real_radius - x, long_h);
+ color2 = calcGradient(real_radius - y, long_h);
+ color3 = calcGradient(long_h - r + x, long_h);
+ color4 = calcGradient(long_h - r + y, long_h);
+
+ //TL = (x1 + r, y1 + r)
+ gradientFillClip(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y,
+ x1 + r - x, y1 + r - y);
+ gradientFillClip(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x,
+ x1 + r - y, y1 + r - x);
+
+ //BL = (x1 + r, y1 + h - r)
+ gradientFillClip(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y,
+ x1 + r - x, y1 + h - r + y);
+ gradientFillClip(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x,
+ x1 + r - y, y1 + h - r + x);
+
+ BE_DRAWCIRCLE_XCOLOR_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ }
+ } else {
+ while (x++ < y) {
+ BE_ALGORITHM();
+
+ colorFillClip<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1,
+ x1 + r - x, y1 + r - y, _clippingArea);
+ colorFillClip<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1,
+ x1 + r - y, y1 + r - x, _clippingArea);
+
+ colorFillClip<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1,
+ x1 + r - x, y1 + h - r + y, _clippingArea);
+ colorFillClip<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1,
+ x1 + r - y, y1 + h - r + x, _clippingArea);
+
+ // do not remove - messes up the drawing at lower resolutions
+ BE_DRAWCIRCLE_CLIP(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py,
+ x1 + w - r, y1 + r, x1 + r, y1 + r, x1 + r, y1 + h - r, x1 + w - r, y1 + h - r);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ int short_h_orig = short_h;
+ while (short_h--) {
+ if (fill_m == kFillGradient) {
+ gradientFillClip(ptr_fill, w + 1, x1, real_radius++, x1, y1 + r + short_h_orig - short_h -1);
+ } else {
+ colorFillClip<PixelType>(ptr_fill, ptr_fill + w + 1, color1, x1, y1 + r + short_h_orig - short_h - 1, _clippingArea);
+ }
+ ptr_fill += pitch;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
const uint8 borderAlpha_t = 0;
const uint8 borderAlpha_r = 127;
@@ -1810,6 +3328,38 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, Vecto
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) {
+ const uint8 borderAlpha_t = 0;
+ const uint8 borderAlpha_r = 127;
+ const uint8 borderAlpha_b = 255;
+ const uint8 borderAlpha_l = 63;
+
+ const uint8 bevelAlpha_t = 255;
+ const uint8 bevelAlpha_r = 31;
+ const uint8 bevelAlpha_b = 0;
+ const uint8 bevelAlpha_l = 127;
+
+ // If only border is visible
+ if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) {
+ if (fill_m == Base::kFillBackground)
+ drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, _bgColor, fill_m);
+ else
+ drawInteriorRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m);
+ }
+
+ //I expect these to work fine with clipping:
+ if (Base::_strokeWidth) {
+ if (r != 0 && _bevel > 0) {
+ drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l);
+ drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l);
+ } else {
+ drawBorderRoundedSquareAlgClip(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255);
+ }
+ }
+}
+
/** CIRCLE ALGORITHM **/
template<typename PixelType>
void VectorRendererSpec<PixelType>::
@@ -1854,7 +3404,47 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawCircleAlgClip(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode fill_m) {
+ int f, ddF_x, ddF_y;
+ int x, y, px, py, sw = 0;
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ PixelType *ptr = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1);
+
+ if (fill_m == kFillDisabled) {
+ while (sw++ < Base::_strokeWidth) {
+ BE_RESET();
+ r--;
+
+ if (IS_IN_CLIP(x1 + y, y1)) *(ptr + y) = color;
+ if (IS_IN_CLIP(x1 - y, y1)) *(ptr - y) = color;
+ if (IS_IN_CLIP(x1, y1 + y)) *(ptr + py) = color;
+ if (IS_IN_CLIP(x1, y1 - y)) *(ptr - py) = color;
+
+ while (x++ < y) {
+ BE_ALGORITHM();
+ BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
+
+ if (Base::_strokeWidth > 1) {
+ BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x - 1, y, px, py, x1, y1, x1, y1, x1, y1, x1, y1);
+ BE_DRAWCIRCLE_CLIP(ptr, ptr, ptr, ptr, x, y, px - pitch, py, x1, y1, x1, y1, x1, y1, x1, y1);
+ }
+ }
+ }
+ } else {
+ colorFillClip<PixelType>(ptr - r, ptr + r, color, x1 - r, y1 + r, _clippingArea);
+ BE_RESET();
+ while (x++ < y) {
+ BE_ALGORITHM();
+ colorFillClip<PixelType>(ptr - x + py, ptr + x + py, color, x1 - x, y1 + y, _clippingArea);
+ colorFillClip<PixelType>(ptr - x - py, ptr + x - py, color, x1 - x, y1 - y, _clippingArea);
+ colorFillClip<PixelType>(ptr - y + px, ptr + y + px, color, x1 - y, y1 + x, _clippingArea);
+ colorFillClip<PixelType>(ptr - y - px, ptr + y - px, color, x1 - y, y1 - x, _clippingArea);
+ }
+ }
+}
/********************************************************************
@@ -1905,6 +3495,54 @@ drawSquareShadow(int x, int y, int w, int h, int offset) {
template<typename PixelType>
void VectorRendererSpec<PixelType>::
+drawSquareShadowClip(int x, int y, int w, int h, int offset) {
+ // Do nothing for empty rects or no shadow offset.
+ if (w <= 0 || h <= 0 || offset <= 0) {
+ return;
+ }
+
+ PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset);
+ int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
+ int i, j, ptr_x = x+w-1, ptr_y = y+offset;
+
+ i = h - offset;
+
+ while (i--) {
+ j = offset;
+ while (j--)
+ blendPixelPtrClip(ptr + j, 0, ((offset - j) << 8) / offset, ptr_x + j, ptr_y);
+ ptr += pitch;
+ ++ptr_y;
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1);
+ ptr_x = x + offset;
+ ptr_y = y + h - 1;
+
+ while (i++ < offset) {
+ j = w - offset;
+ while (j--)
+ blendPixelPtrClip(ptr + j, 0, ((offset - i) << 8) / offset, ptr_x + j, ptr_y);
+ ptr += pitch;
+ ++ptr_y;
+ }
+
+ ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h);
+ ptr_x = x + w;
+ ptr_y = y + h;
+
+ i = 0;
+ while (i++ < offset) {
+ j = offset - 1;
+ while (j--)
+ blendPixelPtrClip(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset), ptr_x + j, ptr_y);
+ ptr += pitch;
+ ++ptr_y;
+ }
+}
+
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
@@ -1942,7 +3580,6 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
while (x++ < y) {
BE_ALGORITHM();
-
if (((1 << x) & hb) == 0) {
blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha);
@@ -1978,6 +3615,83 @@ drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) {
}
}
+template<typename PixelType>
+void VectorRendererSpec<PixelType>::
+drawRoundedSquareShadowClip(int x1, int y1, int r, int w, int h, int offset) {
+ 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;
+
+ // These constants ensure a border of 2px on the left and of each rounded square
+ int xstart = (x1 > 2) ? x1 - 2 : x1;
+ int ystart = y1;
+ int width = w + offset + 2;
+ 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_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r);
+ PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + height - r);
+ PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, 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,
+ xstart + r - y, ystart + r - x);
+
+ // Will create a dark line of pixles if left out
+ if (hb > 0) {
+ blendFillClip(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha,
+ xstart + r - y, ystart + height - r + x);
+ }
+ hb |= (1 << x);
+ }
+
+ if (((1 << y) & hb) == 0) {
+ blendFillClip(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha, xstart + r - x, ystart + r - y);
+ blendFillClip(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha, xstart + r - x, ystart + height - r + y);
+ hb |= (1 << y);
+ }
+ }
+
+ ptr_fill += pitch * r;
+ int orig_short_h = short_h;
+ while (short_h--) {
+ blendFillClip(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha,
+ xstart, ystart + r + orig_short_h - short_h - 1);
+ ptr_fill += pitch;
+ }
+
+ // Make shadow smaller each iteration, and move it one pixel inward
+ xstart += 1;
+ ystart += 1;
+ width -= 2;
+ height -= 2;
+
+ if (_shadowFillMode == kShadowExponential)
+ // Multiply with expfactor
+ alpha = (alpha * (expFactor << 8)) >> 9;
+ }
+}
/******************************************************************************/
diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h
index 3e54608b8e..bee6d4c425 100644
--- a/graphics/VectorRendererSpec.h
+++ b/graphics/VectorRendererSpec.h
@@ -51,14 +51,31 @@ public:
VectorRendererSpec(PixelFormat format);
void drawLine(int x1, int y1, int x2, int y2);
+ void drawLineClip(int x1, int y1, int x2, int y2, Common::Rect clipping);
void drawCircle(int x, int y, int r);
+ void drawCircleClip(int x, int y, int r, Common::Rect clipping);
void drawSquare(int x, int y, int w, int h);
+ void drawSquareClip(int x, int y, int w, int h, Common::Rect clipping);
void drawRoundedSquare(int x, int y, int r, int w, int h);
+ void drawRoundedSquareClip(int x, int y, int r, int w, int h, Common::Rect clipping);
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);
+ 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);
}
+ void drawBeveledSquareClip(int x, int y, int w, int h, int bevel, Common::Rect clipping) {
+ bool useClippingVersions = !(clipping.isEmpty() || clipping.contains(Common::Rect(x, y, x + w, y + h)));
+ if (useClippingVersions) {
+ Common::Rect backup = _clippingArea;
+ _clippingArea = clipping;
+ drawBevelSquareAlgClip(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
+ _clippingArea = backup;
+ } else {
+ drawBevelSquareAlg(x, y, w, h, bevel, _bevelColor, _fgColor, Base::_fillMode != kFillDisabled);
+ }
+ }
void drawString(const Graphics::Font *font, const Common::String &text,
const Common::Rect &area, Graphics::TextAlign alignH,
GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool elipsis, const Common::Rect &textDrawableArea = Common::Rect(0, 0, 0, 0));
@@ -72,14 +89,19 @@ public:
void copyWholeFrame(OSystem *sys) { copyFrame(sys, Common::Rect(0, 0, _activeSurface->w, _activeSurface->h)); }
void fillSurface();
+ void fillSurfaceClip(Common::Rect clipping);
void blitSurface(const Graphics::Surface *source, const Common::Rect &r);
void blitSubSurface(const Graphics::Surface *source, const Common::Rect &r);
+ void blitSubSurfaceClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping);
void blitAlphaBitmap(const Graphics::Surface *source, const Common::Rect &r);
+ void blitAlphaBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const Common::Rect &clipping);
void applyScreenShading(GUI::ThemeEngine::ShadingStyle shadingStyle);
protected:
+ Common::Rect _clippingArea;
+
/**
* Draws a single pixel on the surface with the given coordinates and
* the given color.
@@ -119,6 +141,7 @@ protected:
* @param alpha Alpha intensity of the pixel (0-255)
*/
inline void blendPixelPtr(PixelType *ptr, PixelType color, uint8 alpha);
+ inline void blendPixelPtrClip(PixelType *ptr, PixelType color, uint8 alpha, int x, int y);
/**
* Blends a single pixel on the surface in the given pixel pointer, using supplied color
@@ -152,40 +175,74 @@ protected:
virtual void drawLineAlg(int x1, int y1, int x2, int y2,
uint dx, uint dy, PixelType color);
+ virtual void drawLineAlgClip(int x1, int y1, int x2, int y2,
+ uint dx, uint dy, PixelType color);
+
virtual void drawCircleAlg(int x, int y, int r,
PixelType color, FillMode fill_m);
+ virtual void drawCircleAlgClip(int x, int y, int r,
+ PixelType color, FillMode fill_m);
+
virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h,
PixelType color, FillMode fill_m);
+ virtual void drawRoundedSquareAlgClip(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m);
+
virtual void drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h,
PixelType color, FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l);
+ virtual void drawBorderRoundedSquareAlgClip(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l);
+
virtual void drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h,
PixelType color, FillMode fill_m);
+ virtual void drawInteriorRoundedSquareAlgClip(int x1, int y1, int r, int w, int h,
+ PixelType color, FillMode fill_m);
+
virtual void drawSquareAlg(int x, int y, int w, int h,
PixelType color, FillMode fill_m);
+ virtual void drawSquareAlgClip(int x, int y, int w, int h,
+ PixelType color, FillMode fill_m);
+
virtual void drawTriangleVertAlg(int x, int y, int w, int h,
bool inverted, PixelType color, FillMode fill_m);
+ virtual void drawTriangleVertAlgClip(int x, int y, int w, int h,
+ bool inverted, PixelType color, FillMode fill_m);
+
virtual void drawTriangleFast(int x, int y, int size,
bool inverted, PixelType color, FillMode fill_m);
virtual void drawBevelSquareAlg(int x, int y, int w, int h,
int bevel, PixelType top_color, PixelType bottom_color, bool fill);
+ virtual void drawBevelSquareAlgClip(int x, int y, int w, int h,
+ int bevel, PixelType top_color, PixelType bottom_color, bool fill);
+
virtual void drawTabAlg(int x, int y, int w, int h, int r,
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
*
@@ -197,7 +254,9 @@ protected:
* @param offset Intensity/size of the shadow.
*/
virtual void drawSquareShadow(int x, int y, int w, int h, int offset);
+ virtual void drawSquareShadowClip(int x, int y, int w, int h, int offset);
virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int offset);
+ virtual void drawRoundedSquareShadowClip(int x, int y, int r, int w, int h, int offset);
/**
* Calculates the color gradient on a given point.
@@ -212,6 +271,7 @@ protected:
void precalcGradient(int h);
void gradientFill(PixelType *first, int width, int x, int y);
+ void gradientFillClip(PixelType *first, int width, int x, int y, int realX, int realY);
/**
* Fills several pixels in a row with a given color and the specified alpha blending.
@@ -227,7 +287,20 @@ protected:
while (first != last) blendPixelPtr(first++, color, alpha);
}
+ inline void blendFillClip(PixelType *first, PixelType *last, PixelType color, uint8 alpha, int realX, int realY) {
+ if (_clippingArea.top <= realY && realY < _clippingArea.bottom) {
+ while (first != last) {
+ if (_clippingArea.left <= realX && realX < _clippingArea.right)
+ blendPixelPtr(first++, color, alpha);
+ else
+ ++first;
+ ++realX;
+ }
+ }
+ }
+
void darkenFill(PixelType *first, PixelType *last);
+ void darkenFillClip(PixelType *first, PixelType *last, int x, int y);
const PixelFormat _format;
const PixelType _redMask, _greenMask, _blueMask, _alphaMask;
diff --git a/graphics/nine_patch.cpp b/graphics/nine_patch.cpp
index a193200208..8ac6977eed 100644
--- a/graphics/nine_patch.cpp
+++ b/graphics/nine_patch.cpp
@@ -236,6 +236,41 @@ void NinePatchBitmap::blit(Graphics::Surface &target, int dx, int dy, int dw, in
}
}
+void NinePatchBitmap::blitClip(Graphics::Surface &target, Common::Rect clip, int dx, int dy, int dw, int dh) {
+ /* don't draw bitmaps that are smaller than the fixed area */
+ if (dw < _h._fix || dh < _v._fix)
+ return;
+
+ /* if the bitmap is the same size as the origin, then draw it as-is */
+ if (dw == _width && dh == _height) {
+ Common::Rect r(1, 1, dw, dh);
+
+ _bmp->blitClip(target, clip, dx, dy, Graphics::FLIP_NONE, &r);
+ return;
+ }
+
+ /* only recalculate the offsets if they have changed since the last draw */
+ if (_cached_dw != dw || _cached_dh != dh) {
+ _h.calcOffsets(dw);
+ _v.calcOffsets(dh);
+
+ _cached_dw = dw;
+ _cached_dh = dh;
+ }
+
+ /* draw each region */
+ for (uint i = 0; i < _v._m.size(); ++i) {
+ for (uint j = 0; j < _h._m.size(); ++j) {
+ Common::Rect r(_h._m[j]->offset, _v._m[i]->offset,
+ _h._m[j]->offset + _h._m[j]->length, _v._m[i]->offset + _v._m[i]->length);
+
+ _bmp->blitClip(target, clip, dx + _h._m[j]->dest_offset, dy + _v._m[i]->dest_offset,
+ Graphics::FLIP_NONE, &r, TS_ARGB(255, 255, 255, 255),
+ _h._m[j]->dest_length, _v._m[i]->dest_length);
+ }
+ }
+}
+
NinePatchBitmap::~NinePatchBitmap() {
if (_destroy_bmp)
delete _bmp;
diff --git a/graphics/nine_patch.h b/graphics/nine_patch.h
index c62de3f6e2..45e4e0918a 100644
--- a/graphics/nine_patch.h
+++ b/graphics/nine_patch.h
@@ -83,6 +83,7 @@ public:
~NinePatchBitmap();
void blit(Graphics::Surface &target, int dx, int dy, int dw, int dh);
+ void blitClip(Graphics::Surface &target, Common::Rect clip, int dx, int dy, int dw, int dh);
int getWidth() { return _width; }
int getHeight() { return _height; }
diff --git a/graphics/transparent_surface.cpp b/graphics/transparent_surface.cpp
index 19e7655a93..c2903d42c3 100644
--- a/graphics/transparent_surface.cpp
+++ b/graphics/transparent_surface.cpp
@@ -462,6 +462,139 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p
return retSize;
}
+Common::Rect TransparentSurface::blitClip(Graphics::Surface &target, Common::Rect clippingArea, int posX, int posY, int flipping, Common::Rect *pPartRect, uint color, int width, int height, TSpriteBlendMode blendMode) {
+ Common::Rect retSize;
+ retSize.top = 0;
+ retSize.left = 0;
+ retSize.setWidth(0);
+ retSize.setHeight(0);
+ // Check if we need to draw anything at all
+ int ca = (color >> kAModShift) & 0xff;
+
+ if (ca == 0) {
+ return retSize;
+ }
+
+ // Create an encapsulating surface for the data
+ TransparentSurface srcImage(*this, false);
+ // TODO: Is the data really in the screen format?
+ if (format.bytesPerPixel != 4) {
+ warning("TransparentSurface can only blit 32bpp images, but got %d", format.bytesPerPixel * 8);
+ return retSize;
+ }
+
+ if (pPartRect) {
+
+ int xOffset = pPartRect->left;
+ int yOffset = pPartRect->top;
+
+ if (flipping & FLIP_V) {
+ yOffset = srcImage.h - pPartRect->bottom;
+ }
+
+ if (flipping & FLIP_H) {
+ xOffset = srcImage.w - pPartRect->right;
+ }
+
+ srcImage.pixels = getBasePtr(xOffset, yOffset);
+ srcImage.w = pPartRect->width();
+ srcImage.h = pPartRect->height();
+
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping,
+ pPartRect->left, pPartRect->top, pPartRect->width(), pPartRect->height(), color, width, height);
+ } else {
+
+ debug(6, "Blit(%d, %d, %d, [%d, %d, %d, %d], %08x, %d, %d)", posX, posY, flipping, 0, 0,
+ srcImage.w, srcImage.h, color, width, height);
+ }
+
+ if (width == -1) {
+ width = srcImage.w;
+ }
+ if (height == -1) {
+ height = srcImage.h;
+ }
+
+#ifdef SCALING_TESTING
+ // Hardcode scaling to 66% to test scaling
+ width = width * 2 / 3;
+ height = height * 2 / 3;
+#endif
+
+ Graphics::Surface *img = nullptr;
+ Graphics::Surface *imgScaled = nullptr;
+ byte *savedPixels = nullptr;
+ if ((width != srcImage.w) || (height != srcImage.h)) {
+ // Scale the image
+ img = imgScaled = srcImage.scale(width, height);
+ savedPixels = (byte *)img->getPixels();
+ } else {
+ img = &srcImage;
+ }
+
+ // Handle off-screen clipping
+ if (posY < clippingArea.top) {
+ img->h = MAX(0, (int)img->h - (clippingArea.top - posY));
+ img->setPixels((byte *)img->getBasePtr(0, clippingArea.top - posY));
+ posY = clippingArea.top;
+ }
+
+ if (posX < clippingArea.left) {
+ img->w = MAX(0, (int)img->w - (clippingArea.left - posX));
+ img->setPixels((byte *)img->getBasePtr(clippingArea.left - posX, 0));
+ posX = clippingArea.left;
+ }
+
+ img->w = CLIP((int)img->w, 0, (int)MAX((int)clippingArea.right - posX, 0));
+ img->h = CLIP((int)img->h, 0, (int)MAX((int)clippingArea.bottom - posY, 0));
+
+ if ((img->w > 0) && (img->h > 0)) {
+ int xp = 0, yp = 0;
+
+ int inStep = 4;
+ int inoStep = img->pitch;
+ if (flipping & FLIP_H) {
+ inStep = -inStep;
+ xp = img->w - 1;
+ }
+
+ if (flipping & FLIP_V) {
+ inoStep = -inoStep;
+ yp = img->h - 1;
+ }
+
+ byte *ino = (byte *)img->getBasePtr(xp, yp);
+ byte *outo = (byte *)target.getBasePtr(posX, posY);
+
+ if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_OPAQUE) {
+ doBlitOpaqueFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
+ } else if (color == 0xFFFFFFFF && blendMode == BLEND_NORMAL && _alphaMode == ALPHA_BINARY) {
+ doBlitBinaryFast(ino, outo, img->w, img->h, target.pitch, inStep, inoStep);
+ } else {
+ if (blendMode == BLEND_ADDITIVE) {
+ doBlitAdditiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
+ } else if (blendMode == BLEND_SUBTRACTIVE) {
+ doBlitSubtractiveBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
+ } else {
+ assert(blendMode == BLEND_NORMAL);
+ doBlitAlphaBlend(ino, outo, img->w, img->h, target.pitch, inStep, inoStep, color);
+ }
+ }
+
+ }
+
+ retSize.setWidth(img->w);
+ retSize.setHeight(img->h);
+
+ if (imgScaled) {
+ imgScaled->setPixels(savedPixels);
+ imgScaled->free();
+ delete imgScaled;
+ }
+
+ return retSize;
+}
+
/**
* Writes a color key to the alpha channel of the surface
* @param rKey the red component of the color key
diff --git a/graphics/transparent_surface.h b/graphics/transparent_surface.h
index 0cd7d5b2e9..c0d3d26e52 100644
--- a/graphics/transparent_surface.h
+++ b/graphics/transparent_surface.h
@@ -123,6 +123,14 @@ struct TransparentSurface : public Graphics::Surface {
uint color = TS_ARGB(255, 255, 255, 255),
int width = -1, int height = -1,
TSpriteBlendMode blend = BLEND_NORMAL);
+ Common::Rect blitClip(Graphics::Surface &target, Common::Rect clippingArea,
+ int posX = 0, int posY = 0,
+ int flipping = FLIP_NONE,
+ Common::Rect *pPartRect = nullptr,
+ uint color = TS_ARGB(255, 255, 255, 255),
+ int width = -1, int height = -1,
+ TSpriteBlendMode blend = BLEND_NORMAL);
+
void applyColorKey(uint8 r, uint8 g, uint8 b, bool overwriteAlpha = false);
/**
diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index 0ed020ebb8..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
@@ -862,6 +924,30 @@ 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) {
@@ -881,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;
@@ -896,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
@@ -920,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;
@@ -927,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;
@@ -953,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;
@@ -979,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;
@@ -999,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;
@@ -1020,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;
@@ -1052,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;
@@ -1063,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;
@@ -1084,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;
@@ -1091,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;
@@ -1114,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;
@@ -1142,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;
@@ -1215,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;
@@ -1229,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);
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.h b/gui/ThemeLayout.h
index c4d7e672dd..e738002aa6 100644
--- a/gui/ThemeLayout.h
+++ b/gui/ThemeLayout.h
@@ -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/dialog.cpp b/gui/dialog.cpp
index 50b7755bb3..523227a237 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -113,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/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/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 70f7672c57..d7246fa382 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx
index c73ffa1f08..56a54f8646 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'
diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx
index 43ec0cdee1..a3f06bd0f9 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'
@@ -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'
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 73d055527c..32ca0223c5 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;
@@ -280,7 +305,10 @@ void StaticTextWidget::setAlign(Graphics::TextAlign align) {
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 -
@@ -319,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) {
@@ -418,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
@@ -431,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);
}
}
@@ -466,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 -
@@ -535,7 +566,7 @@ 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 -
@@ -603,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) {
@@ -680,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);
}
}
@@ -717,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 bef90d4382..0a8725ac9e 100644
--- a/gui/widgets/edittext.cpp
+++ b/gui/widgets/edittext.cpp
@@ -97,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();
@@ -105,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 0a1010f8fa..789064e8fd 100644
--- a/gui/widgets/popup.cpp
+++ b/gui/widgets/popup.cpp
@@ -364,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
+ );
}
}
@@ -470,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..784e438952 100644
--- a/gui/widgets/tab.cpp
+++ b/gui/widgets/tab.cpp
@@ -80,6 +80,8 @@ 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;
}
@@ -258,6 +260,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 +274,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 +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), _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() {