/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (C) 2012-24 Miranda NG team (https://miranda-ng.org), Copyright (c) 2000-03 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" extern int g_hottrack, g_hottrack_done; extern BOOL g_inCLCpaint; extern uint8_t saved_alpha; extern uint32_t savedCORNER; extern ImageItem *g_glyphItem; uint8_t __forceinline percent_to_byte(UINT32 percent) { return(uint8_t)((FLOAT)(((FLOAT)percent) / 100) * 255); } COLORREF __forceinline revcolref(COLORREF colref) { return RGB(GetBValue(colref), GetGValue(colref), GetRValue(colref)); } uint32_t __forceinline argb_from_cola(COLORREF col, UINT32 alpha) { return((uint8_t)percent_to_byte(alpha) << 24 | col); } void __forceinline DrawBorderStyle(HDC hdcwnd, RECT *rc, uint32_t BORDERSTYLE) { HPEN hPenOld = nullptr; POINT pt; switch (BORDERSTYLE) { case BDR_RAISEDOUTER: // raised MoveToEx(hdcwnd, rc->left, rc->bottom - 1, &pt); hPenOld = reinterpret_cast(SelectObject(hdcwnd, cfg::dat.hPen3DBright)); LineTo(hdcwnd, rc->left, rc->top); LineTo(hdcwnd, rc->right, rc->top); SelectObject(hdcwnd, cfg::dat.hPen3DDark); MoveToEx(hdcwnd, rc->right - 1, rc->top + 1, &pt); LineTo(hdcwnd, rc->right - 1, rc->bottom - 1); LineTo(hdcwnd, rc->left - 1, rc->bottom - 1); break; case BDR_SUNKENINNER: MoveToEx(hdcwnd, rc->left, rc->bottom - 1, &pt); hPenOld = reinterpret_cast(SelectObject(hdcwnd, cfg::dat.hPen3DDark)); LineTo(hdcwnd, rc->left, rc->top); LineTo(hdcwnd, rc->right, rc->top); MoveToEx(hdcwnd, rc->right - 1, rc->top + 1, &pt); SelectObject(hdcwnd, cfg::dat.hPen3DBright); LineTo(hdcwnd, rc->right - 1, rc->bottom - 1); LineTo(hdcwnd, rc->left, rc->bottom - 1); break; default: DrawEdge(hdcwnd, rc, BORDERSTYLE, BF_RECT | BF_SOFT); break; } if (hPenOld) SelectObject(hdcwnd, hPenOld); } void DrawAlpha(HDC hdcwnd, PRECT rc, uint32_t basecolor, int alpha, uint32_t basecolor2, BOOL transparent, uint8_t FLG_GRADIENT, uint8_t FLG_CORNER, uint32_t BORDERSTYLE, ImageItem *imageItem) { if (rc == nullptr) return; int ulBitmapWidth, ulBitmapHeight; UCHAR ubAlpha = 0xFF; UCHAR ubRedFinal = 0xFF; UCHAR ubGreenFinal = 0xFF; UCHAR ubBlueFinal = 0xFF; LONG realHeight = (rc->bottom - rc->top); LONG realWidth = (rc->right - rc->left); LONG realHeightHalf = realHeight >> 1; if (g_hottrack && g_inCLCpaint) { StatusItems_t *ht = arStatusItems[ID_EXTBKHOTTRACK - ID_STATUS_OFFLINE]; if (ht->IGNORED == 0) { basecolor = ht->COLOR; basecolor2 = ht->COLOR2; alpha = ht->ALPHA; FLG_GRADIENT = ht->GRADIENT; transparent = ht->COLOR2_TRANSPARENT; BORDERSTYLE = ht->BORDERSTYLE; imageItem = ht->imageItem; } g_hottrack_done = 1; } if (imageItem) { IMG_RenderImageItem(hdcwnd, imageItem, rc); return; } if (rc->right < rc->left || rc->bottom < rc->top || (realHeight <= 0) || (realWidth <= 0)) return; if (cfg::dat.bUseFastGradients && !(FLG_CORNER & CORNER_ACTIVE)) { GRADIENT_RECT grect; TRIVERTEX tvtx[2]; int orig = 1, dest = 0; if (!(FLG_GRADIENT & GRADIENT_ACTIVE)) { tvtx[0].Red = tvtx[1].Red = (COLOR16)GetRValue(basecolor) << 8; tvtx[0].Blue = tvtx[1].Blue = (COLOR16)GetBValue(basecolor) << 8; tvtx[0].Green = tvtx[1].Green = (COLOR16)GetGValue(basecolor) << 8; tvtx[0].Alpha = tvtx[1].Alpha = 0; } else { if (FLG_GRADIENT & GRADIENT_LR || FLG_GRADIENT & GRADIENT_TB) { orig = 0; dest = 1; } tvtx[orig].Red = (COLOR16)GetRValue(basecolor) << 8; tvtx[orig].Blue = (COLOR16)GetBValue(basecolor) << 8; tvtx[orig].Green = (COLOR16)GetGValue(basecolor) << 8; tvtx[orig].Alpha = (COLOR16)0; tvtx[dest].Red = (COLOR16)GetRValue(basecolor2) << 8; tvtx[dest].Blue = (COLOR16)GetBValue(basecolor2) << 8; tvtx[dest].Green = (COLOR16)GetGValue(basecolor2) << 8; tvtx[dest].Alpha = (COLOR16)0; } grect.UpperLeft = 0; grect.LowerRight = 1; saved_alpha = (UCHAR)(basecolor >> 24); if (alpha < 100) { LONG width = rc->right - rc->left, height = rc->bottom - rc->top; tvtx[0].x = tvtx[0].y = 0; tvtx[1].x = width; tvtx[1].y = height; basecolor = argb_from_cola(revcolref(basecolor), alpha); basecolor2 = argb_from_cola(revcolref(basecolor2), alpha); BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = percent_to_byte((UINT32)alpha); bf.AlphaFormat = 0; // so it will use our specified alpha value HDC hdc = CreateCompatibleDC(hdcwnd); if (!hdc) return; HBITMAP hbm = CreateCompatibleBitmap(hdcwnd, width, height); HBITMAP hbmOld = reinterpret_cast(SelectObject(hdc, hbm)); GdiGradientFill(hdc, tvtx, 2, &grect, 1, (FLG_GRADIENT & GRADIENT_TB || FLG_GRADIENT & GRADIENT_BT) ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H); GdiAlphaBlend(hdcwnd, rc->left, rc->top, width, height, hdc, 0, 0, width, height, bf); SelectObject(hdc, hbmOld); DeleteObject(hbm); DeleteDC(hdc); } else { tvtx[0].x = rc->left; tvtx[0].y = rc->top; tvtx[1].x = rc->right; tvtx[1].y = rc->bottom; GdiGradientFill(hdcwnd, tvtx, 2, &grect, 1, (FLG_GRADIENT & GRADIENT_TB || FLG_GRADIENT & GRADIENT_BT) ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H); } DrawBorderStyle(hdcwnd, rc, BORDERSTYLE); //_DebugPopup(0, "using gradient fill"); return; } HDC hdc = CreateCompatibleDC(hdcwnd); if (!hdc) return; BITMAPINFO bmi; memset(&bmi, 0, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); if (FLG_GRADIENT & GRADIENT_ACTIVE && (FLG_GRADIENT & GRADIENT_LR || FLG_GRADIENT & GRADIENT_RL)) { bmi.bmiHeader.biWidth = ulBitmapWidth = realWidth; bmi.bmiHeader.biHeight = ulBitmapHeight = 1; } else if (FLG_GRADIENT & GRADIENT_ACTIVE && (FLG_GRADIENT & GRADIENT_TB || FLG_GRADIENT & GRADIENT_BT)) { bmi.bmiHeader.biWidth = ulBitmapWidth = 1; bmi.bmiHeader.biHeight = ulBitmapHeight = realHeight; } else { bmi.bmiHeader.biWidth = ulBitmapWidth = 1; bmi.bmiHeader.biHeight = ulBitmapHeight = 1; } bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4; void *pvBits; HBITMAP hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, nullptr, 0x0); if (hbitmap == nullptr || pvBits == nullptr) { DeleteDC(hdc); return; } HBITMAP holdbitmap = reinterpret_cast(SelectObject(hdc, hbitmap)); // convert basecolor to RGB and then merge alpha so its ARGB basecolor = argb_from_cola(revcolref(basecolor), alpha); basecolor2 = argb_from_cola(revcolref(basecolor2), alpha); UCHAR ubRed = (UCHAR)(basecolor >> 16); UCHAR ubGreen = (UCHAR)(basecolor >> 8); UCHAR ubBlue = (UCHAR)basecolor; UCHAR ubRed2 = (UCHAR)(basecolor2 >> 16); UCHAR ubGreen2 = (UCHAR)(basecolor2 >> 8); UCHAR ubBlue2 = (UCHAR)basecolor2; //DRAW BASE - make corner space 100% transparent for (int y = 0; y < ulBitmapHeight; y++) { for (int x = 0; x < ulBitmapWidth; x++) { if (FLG_GRADIENT & GRADIENT_ACTIVE) { if (FLG_GRADIENT & GRADIENT_LR || FLG_GRADIENT & GRADIENT_RL) { int realx = x + realHeightHalf; realx = realx > ulBitmapWidth ? ulBitmapWidth : realx; gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, FLG_GRADIENT, transparent, realx, &ubAlpha); } else if (FLG_GRADIENT & GRADIENT_TB || FLG_GRADIENT & GRADIENT_BT) gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, FLG_GRADIENT, transparent, y, &ubAlpha); float fAlphaFactor = (float)ubAlpha / (float)0xff; ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } else { ubAlpha = percent_to_byte(alpha); ubRedFinal = ubRed; ubGreenFinal = ubGreen; ubBlueFinal = ubBlue; float fAlphaFactor = (float)ubAlpha / (float)0xff; ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } } } BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = (UCHAR)(basecolor >> 24); bf.AlphaFormat = AC_SRC_ALPHA; // so it will use our specified alpha value GdiAlphaBlend(hdcwnd, rc->left + realHeightHalf, rc->top, (realWidth - realHeightHalf * 2), realHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf); SelectObject(hdc, holdbitmap); DeleteObject(hbitmap); saved_alpha = (UCHAR)(basecolor >> 24); // corners HBRUSH holdbrush; HBRUSH BrMask = CreateSolidBrush(RGB(0xFF, 0x00, 0xFF)); { bmi.bmiHeader.biWidth = ulBitmapWidth = realHeightHalf; bmi.bmiHeader.biHeight = ulBitmapHeight = realHeight; bmi.bmiHeader.biSizeImage = ulBitmapWidth * ulBitmapHeight * 4; if (ulBitmapWidth <= 0 || ulBitmapHeight <= 0) { DeleteDC(hdc); DeleteObject(BrMask); return; } // TL+BL CORNER hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, nullptr, 0x0); if (hbitmap == nullptr || pvBits == nullptr) { DeleteObject(BrMask); DeleteDC(hdc); return; } holdbrush = reinterpret_cast(SelectObject(hdc, BrMask)); holdbitmap = reinterpret_cast(SelectObject(hdc, hbitmap)); RoundRect(hdc, -1, -1, ulBitmapWidth * 2 + 1, (realHeight + 1), cfg::dat.cornerRadius << 1, cfg::dat.cornerRadius << 1); for (int y = 0; y < ulBitmapHeight; y++) { for (int x = 0; x < ulBitmapWidth; x++) { if (((((UINT32 *)pvBits)[x + y * ulBitmapWidth]) << 8) == 0xFF00FF00 || (y< ulBitmapHeight >> 1 && !(FLG_CORNER & CORNER_BL && FLG_CORNER & CORNER_ACTIVE)) || (y > ulBitmapHeight >> 2 && !(FLG_CORNER & CORNER_TL && FLG_CORNER & CORNER_ACTIVE))) { if (FLG_GRADIENT & GRADIENT_ACTIVE) { if (FLG_GRADIENT & GRADIENT_LR || FLG_GRADIENT & GRADIENT_RL) gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, realWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, FLG_GRADIENT, transparent, x, &ubAlpha); else if (FLG_GRADIENT & GRADIENT_TB || FLG_GRADIENT & GRADIENT_BT) gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, FLG_GRADIENT, transparent, y, &ubAlpha); float fAlphaFactor = (float)ubAlpha / (float)0xff; ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } else { ubAlpha = percent_to_byte(alpha); ubRedFinal = ubRed; ubGreenFinal = ubGreen; ubBlueFinal = ubBlue; float fAlphaFactor = (float)ubAlpha / (float)0xff; ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } } } } GdiAlphaBlend(hdcwnd, rc->left, rc->top, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf); SelectObject(hdc, holdbitmap); DeleteObject(hbitmap); // TR+BR CORNER hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, nullptr, 0x0); //SelectObject(hdc, BrMask); // already BrMask? holdbitmap = reinterpret_cast(SelectObject(hdc, hbitmap)); RoundRect(hdc, -1 - ulBitmapWidth, -1, ulBitmapWidth + 1, (realHeight + 1), cfg::dat.cornerRadius << 1, cfg::dat.cornerRadius << 1); for (int y = 0; y < ulBitmapHeight; y++) { for (int x = 0; x < ulBitmapWidth; x++) { if (((((UINT32 *)pvBits)[x + y * ulBitmapWidth]) << 8) == 0xFF00FF00 || (y< ulBitmapHeight >> 1 && !(FLG_CORNER & CORNER_BR && FLG_CORNER & CORNER_ACTIVE)) || (y > ulBitmapHeight >> 1 && !(FLG_CORNER & CORNER_TR && FLG_CORNER & CORNER_ACTIVE))) { if (FLG_GRADIENT & GRADIENT_ACTIVE) { if (FLG_GRADIENT & GRADIENT_LR || FLG_GRADIENT & GRADIENT_RL) { int realx = x + realWidth; realx = realx > realWidth ? realWidth : realx; gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, realWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, FLG_GRADIENT, transparent, realx, &ubAlpha); } else if (FLG_GRADIENT & GRADIENT_TB || FLG_GRADIENT & GRADIENT_BT) gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, FLG_GRADIENT, transparent, y, &ubAlpha); float fAlphaFactor = (float)ubAlpha / (float)0xff; ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } else { ubAlpha = percent_to_byte(alpha); ubRedFinal = ubRed; ubGreenFinal = ubGreen; ubBlueFinal = ubBlue; float fAlphaFactor = (float)ubAlpha / (float)0xff; ((UINT32 *)pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } } } } GdiAlphaBlend(hdcwnd, rc->right - realHeightHalf, rc->top, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf); } DrawBorderStyle(hdcwnd, rc, BORDERSTYLE); SelectObject(hdc, holdbitmap); DeleteObject(hbitmap); SelectObject(hdc, holdbrush); DeleteObject(BrMask); DeleteDC(hdc); } void __inline gradientHorizontal(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal, ULONG ulBitmapWidth, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2, UCHAR ubGreen2, UCHAR ubBlue2, uint32_t FLG_GRADIENT, BOOL transparent, UINT32 x, UCHAR *ubAlpha) { FLOAT fSolidMulti, fInvSolidMulti; // solid to transparent if (transparent) { *ubAlpha = (UCHAR)((float)x / (float)ulBitmapWidth * 255); *ubAlpha = FLG_GRADIENT & GRADIENT_LR ? 0xFF - (*ubAlpha) : (*ubAlpha); *ubRedFinal = ubRed; *ubGreenFinal = ubGreen; *ubBlueFinal = ubBlue; } else { // solid to solid2 if (FLG_GRADIENT & GRADIENT_LR) { fSolidMulti = ((float)x / (float)ulBitmapWidth); fInvSolidMulti = 1 - fSolidMulti; } else { fInvSolidMulti = ((float)x / (float)ulBitmapWidth); fSolidMulti = 1 - fInvSolidMulti; } *ubRedFinal = (UCHAR)(((float)ubRed * (float)fInvSolidMulti) + ((float)ubRed2 * (float)fSolidMulti)); *ubGreenFinal = (UCHAR)(((float)ubGreen * (float)fInvSolidMulti) + ((float)ubGreen2 * (float)fSolidMulti)); *ubBlueFinal = (UCHAR)(((float)ubBlue * (float)fInvSolidMulti) + ((float)ubBlue2 * (float)fSolidMulti)); *ubAlpha = 0xFF; } } void __inline gradientVertical(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal, ULONG ulBitmapHeight, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2, UCHAR ubGreen2, UCHAR ubBlue2, uint32_t FLG_GRADIENT, BOOL transparent, UINT32 y, UCHAR *ubAlpha) { FLOAT fSolidMulti, fInvSolidMulti; // solid to transparent if (transparent) { *ubAlpha = (UCHAR)((float)y / (float)ulBitmapHeight * 255); *ubAlpha = FLG_GRADIENT & GRADIENT_BT ? 0xFF - *ubAlpha : *ubAlpha; *ubRedFinal = ubRed; *ubGreenFinal = ubGreen; *ubBlueFinal = ubBlue; } else { // solid to solid2 if (FLG_GRADIENT & GRADIENT_BT) { fSolidMulti = ((float)y / (float)ulBitmapHeight); fInvSolidMulti = 1 - fSolidMulti; } else { fInvSolidMulti = ((float)y / (float)ulBitmapHeight); fSolidMulti = 1 - fInvSolidMulti; } *ubRedFinal = (UCHAR)(((float)ubRed * (float)fInvSolidMulti) + ((float)ubRed2 * (float)fSolidMulti)); *ubGreenFinal = (UCHAR)(((float)ubGreen * (float)fInvSolidMulti) + ((float)ubGreen2 * (float)fSolidMulti)); *ubBlueFinal = (UCHAR)(((float)ubBlue * (float)fInvSolidMulti) + ((float)ubBlue2 * (float)fSolidMulti)); *ubAlpha = 0xFF; } } /* * render a skin image to the given rect. * all parameters are in ImageItem already pre-configured */ // XXX add support for more stretching options (stretch/tile divided image parts etc. void __fastcall IMG_RenderImageItem(HDC hdc, ImageItem *item, RECT *rc) { uint8_t l = item->bLeft, r = item->bRight, t = item->bTop, b = item->bBottom; LONG width = rc->right - rc->left; LONG height = rc->bottom - rc->top; BOOL isGlyph = (item->dwFlags & IMAGE_GLYPH) && g_glyphItem; HDC hdcSrc = isGlyph ? g_glyphItem->hdc : item->hdc; LONG srcOrigX = isGlyph ? item->glyphMetrics[0] : 0; LONG srcOrigY = isGlyph ? item->glyphMetrics[1] : 0; if (item->dwFlags & IMAGE_FLAG_DIVIDED) { // top 3 items GdiAlphaBlend(hdc, rc->left, rc->top, l, t, hdcSrc, srcOrigX, srcOrigY, l, t, item->bf); GdiAlphaBlend(hdc, rc->left + l, rc->top, width - l - r, t, hdcSrc, srcOrigX + l, srcOrigY, item->inner_width, t, item->bf); GdiAlphaBlend(hdc, rc->right - r, rc->top, r, t, hdcSrc, srcOrigX + (item->width - r), srcOrigY, r, t, item->bf); // middle 3 items GdiAlphaBlend(hdc, rc->left, rc->top + t, l, height - t - b, hdcSrc, srcOrigX, srcOrigY + t, l, item->inner_height, item->bf); if (item->dwFlags & IMAGE_FILLSOLID && item->fillBrush) { RECT rcFill; rcFill.left = rc->left + l; rcFill.top = rc->top + t; rcFill.right = rc->right - r; rcFill.bottom = rc->bottom - b; FillRect(hdc, &rcFill, item->fillBrush); } else GdiAlphaBlend(hdc, rc->left + l, rc->top + t, width - l - r, height - t - b, hdcSrc, srcOrigX + l, srcOrigY + t, item->inner_width, item->inner_height, item->bf); GdiAlphaBlend(hdc, rc->right - r, rc->top + t, r, height - t - b, hdcSrc, srcOrigX + (item->width - r), srcOrigY + t, r, item->inner_height, item->bf); // bottom 3 items GdiAlphaBlend(hdc, rc->left, rc->bottom - b, l, b, hdcSrc, srcOrigX, srcOrigY + (item->height - b), l, b, item->bf); GdiAlphaBlend(hdc, rc->left + l, rc->bottom - b, width - l - r, b, hdcSrc, srcOrigX + l, srcOrigY + (item->height - b), item->inner_width, b, item->bf); GdiAlphaBlend(hdc, rc->right - r, rc->bottom - b, r, b, hdcSrc, srcOrigX + (item->width - r), srcOrigY + (item->height - b), r, b, item->bf); } else { switch (item->bStretch) { case IMAGE_STRETCH_H: // tile image vertically, stretch to width { LONG top = rc->top; do { if (top + item->height <= rc->bottom) { GdiAlphaBlend(hdc, rc->left, top, width, item->height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf); top += item->height; } else { GdiAlphaBlend(hdc, rc->left, top, width, rc->bottom - top, hdcSrc, srcOrigX, srcOrigY, item->width, rc->bottom - top, item->bf); break; } } while (true); } break; case IMAGE_STRETCH_V: // tile horizontally, stretch to height { LONG left = rc->left; do { if (left + item->width <= rc->right) { GdiAlphaBlend(hdc, left, rc->top, item->width, height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf); left += item->width; } else { GdiAlphaBlend(hdc, left, rc->top, rc->right - left, height, hdcSrc, srcOrigX, srcOrigY, rc->right - left, item->height, item->bf); break; } } while (true); } break; case IMAGE_STRETCH_B: // stretch the image in both directions... GdiAlphaBlend(hdc, rc->left, rc->top, width, height, hdcSrc, srcOrigX, srcOrigY, item->width, item->height, item->bf); break; } } }