/* * Miranda NG: the free IM client for Microsoft* Windows* * * Copyright (c) 2000-09 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. * * part of tabSRMM messaging plugin for Miranda. * * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors * * Implements the skinning engine and most parts of the aero support in * tabSRMM 3.x+ * */ #include "commonheaders.h" static SKINDESC my_default_skin[] = { IDR_SKIN_AERO, _T("tabskin_aero.png"), IDR_SKIN_AERO_GLOW, _T("tabskin_aero_glow.png"), IDR_SKIN_AERO_SWITCHBAR, _T("tabskin_aero_button.png"), IDR_SKIN_LOGO, _T("unknown.png") }; CSkin* Skin = 0; static void __inline gradientVertical(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal, ULONG ulBitmapHeight, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2, UCHAR ubGreen2, UCHAR ubBlue2, DWORD FLG_GRADIENT, BOOL transparent, UINT32 y, UCHAR *ubAlpha); static void __inline gradientHorizontal(UCHAR *ubRedFinal, UCHAR *ubGreenFinal, UCHAR *ubBlueFinal, ULONG ulBitmapWidth, UCHAR ubRed, UCHAR ubGreen, UCHAR ubBlue, UCHAR ubRed2, UCHAR ubGreen2, UCHAR ubBlue2, DWORD FLG_GRADIENT, BOOL transparent, UINT32 x, UCHAR *ubAlpha); UINT nextButtonID; ButtonSet g_ButtonSet = {0}; #define NR_MAXSKINICONS 100 /* * initialize static class data */ int CSkin::m_bAvatarBorderType = 0; COLORREF CSkin::m_avatarBorderClr = 0; COLORREF CSkin::m_tmp_tb_low = 0, CSkin::m_tmp_tb_high = 0; COLORREF CSkin::m_sideBarContainerBG; BLENDFUNCTION CSkin::m_default_bf = {0}; // a global blend function, used in various places // when you use it, reset SourceConstantAlpha to 255 and // the blending mode to AC_SRC_ALPHA. bool CSkin::m_bClipBorder = false, CSkin::m_DisableScrollbars = false, CSkin::m_skinEnabled = false, CSkin::m_frameSkins = false; char CSkin::m_SkinnedFrame_left = 0, CSkin::m_SkinnedFrame_right = 0, CSkin::m_SkinnedFrame_bottom = 0, CSkin::m_SkinnedFrame_caption = 0; char CSkin::m_realSkinnedFrame_left = 0; char CSkin::m_realSkinnedFrame_right = 0; char CSkin::m_realSkinnedFrame_bottom = 0; char CSkin::m_realSkinnedFrame_caption = 0; int CSkin::m_titleBarLeftOff = 0, CSkin::m_titleButtonTopOff = 0, CSkin::m_captionOffset = 0, CSkin::m_captionPadding = 0, CSkin::m_titleBarRightOff = 0, CSkin::m_sidebarTopOffset = 0, CSkin::m_sidebarBottomOffset = 0, CSkin::m_bRoundedCorner = 0; CImageItem* CSkin::m_switchBarItem = 0, *CSkin::m_tabTop = 0, *CSkin::m_tabBottom = 0, *CSkin::m_tabGlowTop = 0, *CSkin::m_tabGlowBottom = 0; bool CSkin::m_fAeroSkinsValid = false; SIZE CSkin::m_titleBarButtonSize = {0}; COLORREF CSkin::m_ContainerColorKey = 0, CSkin::m_dwmColorRGB = 0, CSkin::m_DefaultFontColor = 0; HBRUSH CSkin::m_ContainerColorKeyBrush = 0, CSkin::m_MenuBGBrush = 0; HPEN CSkin::m_SkinLightShadowPen = 0, CSkin::m_SkinDarkShadowPen = 0; HICON CSkin::m_closeIcon = 0, CSkin::m_maxIcon = 0, CSkin::m_minIcon = 0; UINT CSkin::m_aeroEffect = 0; DWORD CSkin::m_glowSize = 0; HBRUSH CSkin::m_BrushBack = 0, CSkin::m_BrushFill = 0; HBITMAP CSkin::m_tabCloseBitmap = 0, CSkin::m_tabCloseOldBitmap = 0; HDC CSkin::m_tabCloseHDC = 0; /* * aero effects */ AeroEffect CSkin::m_currentAeroEffect; AeroEffect* CSkin::m_pCurrentAeroEffect = 0; AeroEffect CSkin::m_aeroEffects[AERO_EFFECT_LAST] = { { LPGENT("No effect"), 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0 }, { LPGENT("Milky Glass"), 0xf5f5f5, /* base color */ 0xaaaaaa, /* gradient color */ 70, /* base alpha */ 0, /* final alpha */ CORNER_ALL, /* corner type */ GRADIENT_TB + 1, /* gradient type */ 8, /* corner radius */ 8, /* glow size (0 means no glowing text, colors can be used) */ 0, /* background color (black = transparency) */ 0xf0f0f0, /* toolbar first color (if 0, use custom gradient color) */ 0, /* toolbar 2nd gradient color (0 = use aero theme color, -1 = use custom gradient color */ AeroEffectCallback_Milk /* callback function to render the effect */ }, { LPGENT("Carbon"), 0xf0f0f0, 0x000000, 75, 0, CORNER_ALL, GRADIENT_TB + 1, 6, 8, 0, 0xf0f0f0, 0, AeroEffectCallback_Carbon }, { LPGENT("Semi transparent, custom colors"), 0xffffff, 0x444444, 60, 0, CORNER_ALL, GRADIENT_TB + 1, 6, 0, 0x0, 0xf0f0f0, 0, AeroEffectCallback_Solid }, { LPGENT("Silver shadow"), 0xffffff, 0xa0a0a0, 80, 220, 0, GRADIENT_TB + 1, 1, 0, 0xc0c0c0, 0xf0f0f0, 0x707070, AeroEffectCallback_Solid }, { LPGENT("Custom (use own gradient colors)"), 0xffffff, 0xa0a0a0, 80, 220, 0, GRADIENT_TB + 1, 1, 0, 0xc0c0c0, -1, -1, AeroEffectCallback_Solid } }; /* * definition of the availbale skin items */ CSkinItem SkinItems[] = { {_T("Container"), "TSKIN_Container", ID_EXTBKCONTAINER, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Toolbar"), "TSKIN_Container", ID_EXTBKBUTTONBAR, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("{-}Buttonpressed"), "TSKIN_BUTTONSPRESSED", ID_EXTBKBUTTONSPRESSED, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Buttonnotpressed"), "TSKIN_BUTTONSNPRESSED", ID_EXTBKBUTTONSNPRESSED, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Buttonmouseover"), "TSKIN_BUTTONSMOUSEOVER", ID_EXTBKBUTTONSMOUSEOVER, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Infopanelfield"), "TSKIN_INFOPANELFIELD", ID_EXTBKINFOPANEL, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Titlebutton"), "TSKIN_TITLEBUTTON", ID_EXTBKTITLEBUTTON, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Titlebuttonmouseover"), "TSKIN_TITLEBUTTONHOVER", ID_EXTBKTITLEBUTTONMOUSEOVER, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Titlebuttonpressed"), "TSKIN_TITLEBUTTONPRESSED", ID_EXTBKTITLEBUTTONPRESSED, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabpage"), "TSKIN_TABPAGE", ID_EXTBKTABPAGE, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabitem"), "TSKIN_TABITEM", ID_EXTBKTABITEM, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabitem_active"), "TSKIN_TABITEMACTIVE", ID_EXTBKTABITEMACTIVE, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabitem_bottom"), "TSKIN_TABITEMBOTTOM", ID_EXTBKTABITEMBOTTOM, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabitem_active_bottom"), "TSKIN_TABITEMACTIVEBOTTOM", ID_EXTBKTABITEMACTIVEBOTTOM, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Frame"), "TSKIN_FRAME", ID_EXTBKFRAME, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("MessageLog"), "TSKIN_MLOG", ID_EXTBKHISTORY, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("InputArea"), "TSKIN_INPUT", ID_EXTBKINPUTAREA, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("FrameInactive"), "TSKIN_FRAMEINACTIVE", ID_EXTBKFRAMEINACTIVE, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabitem_hottrack"), "TSKIN_TABITEMHOTTRACK", ID_EXTBKTABITEMHOTTRACK, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Tabitem_hottrack_bottom"), "TSKIN_TABITEMHOTTRACKBOTTOM", ID_EXTBKTABITEMHOTTRACKBOTTOM, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Statusbarpanel"), "TSKIN_STATUSBARPANEL", ID_EXTBKSTATUSBARPANEL, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Statusbar"), "TSKIN_STATUSBAR", ID_EXTBKSTATUSBAR, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("Userlist"), "TSKIN_USERLIST", ID_EXTBKUSERLIST, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }, {_T("InfoPanelBackground"), "TSKIN_INFOPANELBG", ID_EXTBKINFOPANELBG, 8, CLCDEFAULT_CORNER, 0xf0f0f0, 0x42b1ff, 1, CLCDEFAULT_TEXTCOLOR, 40, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE, 0, 0 }, {_T("Sidebar Background"), "TSKIN_SIDEBARBG", ID_EXTBKSIDEBARBG, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, 0xb2e1ff, 0xb2e1ff, 1, CLCDEFAULT_TEXTCOLOR, 40, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE, 0, 0 } }; static CSkinItem _defInfoPanel = { _T("InfoPanelBackground"), "TSKIN_INFOPANELBG", ID_EXTBKINFOPANELBG, 8, CLCDEFAULT_CORNER, 0xf0f0f0, 0x62caff, 0, CLCDEFAULT_TEXTCOLOR, 255, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE, 0, 0 }; static BYTE __inline percent_to_byte(UINT32 percent) { return(BYTE)((FLOAT)(((FLOAT) percent) / 100) * 255); } static COLORREF __inline revcolref(COLORREF colref) { return RGB(GetBValue(colref), GetGValue(colref), GetRValue(colref)); } static DWORD __inline argb_from_cola(COLORREF col, UINT32 alpha) { return((BYTE) percent_to_byte(alpha) << 24 | col); } void TSAPI DrawAlpha(HDC hDC, PRECT rc, DWORD clr_base, int alpha, DWORD clr_dest, BYTE clr_dest_trans, BYTE bGradient, BYTE bCorner, DWORD dwRadius, CImageItem *imageItem) { HBRUSH BrMask; HBRUSH holdbrush; HDC hdc; BLENDFUNCTION bf; HBITMAP hbitmap; HBITMAP holdbitmap; BITMAPINFO bmi; VOID *pvBits; UINT32 x, y; ULONG ulBitmapWidth, ulBitmapHeight; UCHAR ubAlpha = 0xFF; UCHAR ubRedFinal = 0xFF; UCHAR ubGreenFinal = 0xFF; UCHAR ubBlueFinal = 0xFF; UCHAR ubRed; UCHAR ubGreen; UCHAR ubBlue; UCHAR ubRed2; UCHAR ubGreen2; UCHAR ubBlue2; int realx; FLOAT fAlphaFactor; LONG realHeight = (rc->bottom - rc->top); LONG realWidth = (rc->right - rc->left); LONG realHeightHalf = realHeight >> 1; if (rc == NULL) return; if (imageItem) { imageItem->Render(hDC, rc, false); return; } if (rc->right < rc->left || rc->bottom < rc->top || (realHeight <= 0) || (realWidth <= 0)) return; /* * use GDI fast gradient drawing when no corner radi exist */ if (bCorner == 0 && dwRadius == 0) { GRADIENT_RECT grect; TRIVERTEX tvtx[2]; int orig = 1, dest = 0; if (bGradient & GRADIENT_LR || bGradient & GRADIENT_TB) { orig = 0; dest = 1; } tvtx[0].x = rc->left; tvtx[0].y = rc->top; tvtx[1].x = rc->right; tvtx[1].y = rc->bottom; tvtx[orig].Red = (COLOR16)GetRValue(clr_base) << 8; tvtx[orig].Blue = (COLOR16)GetBValue(clr_base) << 8; tvtx[orig].Green = (COLOR16)GetGValue(clr_base) << 8; tvtx[orig].Alpha = (COLOR16) alpha << 8; tvtx[dest].Red = (COLOR16)GetRValue(clr_dest) << 8; tvtx[dest].Blue = (COLOR16)GetBValue(clr_dest) << 8; tvtx[dest].Green = (COLOR16)GetGValue(clr_dest) << 8; tvtx[dest].Alpha = (COLOR16) alpha << 8; grect.UpperLeft = 0; grect.LowerRight = 1; GdiGradientFill(hDC, tvtx, 2, &grect, 1, (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT) ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H); return; } hdc = CreateCompatibleDC(hDC); if (!hdc) return; ZeroMemory(&bmi, sizeof(BITMAPINFO)); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); if (bGradient & GRADIENT_ACTIVE && (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL)) { bmi.bmiHeader.biWidth = ulBitmapWidth = realWidth; bmi.bmiHeader.biHeight = ulBitmapHeight = 1; } else if (bGradient & GRADIENT_ACTIVE && (bGradient & GRADIENT_TB || bGradient & 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; if (ulBitmapWidth <= 0 || ulBitmapHeight <= 0) return; hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0); if (hbitmap == NULL || pvBits == NULL) { DeleteDC(hdc); return; } holdbitmap = (HBITMAP)SelectObject(hdc, hbitmap); // convert basecolor to RGB and then merge alpha so its ARGB clr_base = argb_from_cola(revcolref(clr_base), alpha); clr_dest = argb_from_cola(revcolref(clr_dest), alpha); ubRed = (UCHAR)(clr_base >> 16); ubGreen = (UCHAR)(clr_base >> 8); ubBlue = (UCHAR) clr_base; ubRed2 = (UCHAR)(clr_dest >> 16); ubGreen2 = (UCHAR)(clr_dest >> 8); ubBlue2 = (UCHAR) clr_dest; //DRAW BASE - make corner space 100% transparent for (y = 0; y < ulBitmapHeight; y++) { for (x = 0 ; x < ulBitmapWidth ; x++) { if (bGradient & GRADIENT_ACTIVE) { if (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL) { realx = x + realHeightHalf; realx = (ULONG) realx > ulBitmapWidth ? ulBitmapWidth : realx; gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, realx, &ubAlpha); } else if (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT) gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, y, &ubAlpha); 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; fAlphaFactor = (float) ubAlpha / (float) 0xff; ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } } } bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = (UCHAR)(clr_base >> 24); bf.AlphaFormat = AC_SRC_ALPHA; // so it will use our specified alpha value GdiAlphaBlend(hDC, rc->left + realHeightHalf, rc->top, (realWidth - realHeightHalf * 2), realHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf); SelectObject(hdc, holdbitmap); DeleteObject(hbitmap); // corners 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, NULL, 0x0); if (hbitmap == 0 || pvBits == NULL) { DeleteObject(BrMask); DeleteDC(hdc); return; } holdbrush = (HBRUSH)SelectObject(hdc, BrMask); holdbitmap = (HBITMAP)SelectObject(hdc, hbitmap); RoundRect(hdc, -1, -1, ulBitmapWidth * 2 + 1, (realHeight + 1), dwRadius, dwRadius); for (y = 0; y < ulBitmapHeight; y++) { for (x = 0; x < ulBitmapWidth; x++) { if (((((UINT32 *) pvBits)[x + y * ulBitmapWidth]) << 8) == 0xFF00FF00 || (y < ulBitmapHeight >> 1 && !(bCorner & CORNER_BL && bCorner & CORNER_ACTIVE)) || (y > ulBitmapHeight >> 2 && !(bCorner & CORNER_TL && bCorner & CORNER_ACTIVE))) { if (bGradient & GRADIENT_ACTIVE) { if (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL) gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, realWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, x, &ubAlpha); else if (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT) gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, y, &ubAlpha); 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; fAlphaFactor = (float) ubAlpha / (float) 0xff; ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } } } } GdiAlphaBlend(hDC, 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, NULL, 0x0); //SelectObject(hdc, BrMask); // already BrMask? holdbitmap = (HBITMAP)SelectObject(hdc, hbitmap); RoundRect(hdc, -1 - ulBitmapWidth, -1, ulBitmapWidth + 1, (realHeight + 1), dwRadius, dwRadius); for (y = 0; y < ulBitmapHeight; y++) { for (x = 0; x < ulBitmapWidth; x++) { if (((((UINT32 *) pvBits)[x + y * ulBitmapWidth]) << 8) == 0xFF00FF00 || (y < ulBitmapHeight >> 1 && !(bCorner & CORNER_BR && bCorner & CORNER_ACTIVE)) || (y > ulBitmapHeight >> 1 && !(bCorner & CORNER_TR && bCorner & CORNER_ACTIVE))) { if (bGradient & GRADIENT_ACTIVE) { if (bGradient & GRADIENT_LR || bGradient & GRADIENT_RL) { realx = x + realWidth; realx = realx > realWidth ? realWidth : realx; gradientHorizontal(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, realWidth, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, realx, &ubAlpha); } else if (bGradient & GRADIENT_TB || bGradient & GRADIENT_BT) gradientVertical(&ubRedFinal, &ubGreenFinal, &ubBlueFinal, ulBitmapHeight, ubRed, ubGreen, ubBlue, ubRed2, ubGreen2, ubBlue2, bGradient, clr_dest_trans, y, &ubAlpha); 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; fAlphaFactor = (float) ubAlpha / (float) 0xff; ((UINT32 *) pvBits)[x + y * ulBitmapWidth] = (ubAlpha << 24) | ((UCHAR)(ubRedFinal * fAlphaFactor) << 16) | ((UCHAR)(ubGreenFinal * fAlphaFactor) << 8) | ((UCHAR)(ubBlueFinal * fAlphaFactor)); } } } } GdiAlphaBlend(hDC, rc->right - realHeightHalf, rc->top, ulBitmapWidth, ulBitmapHeight, hdc, 0, 0, ulBitmapWidth, ulBitmapHeight, bf); } 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, DWORD 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)((UCHAR)(((float) ubGreen * (float) fInvSolidMulti)) + (((float) ubGreen2 * (float) fSolidMulti))); *ubBlueFinal = (UCHAR)((((float) ubBlue * (float) fInvSolidMulti)) + (UCHAR)(((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, DWORD 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)) + (UCHAR)(((float) ubBlue2 * (float) fSolidMulti)); *ubAlpha = 0xFF; } } /** * Renders the image item to the given target device context and rectangle * * @param hdc HDC: target device context * @param rc RECT *: client rectangle inside the target DC. * @param fIgnoreGlyph: bool: will ignore any glyph item. Set it to true when * using this function from _outside_ a skin */ void __fastcall CImageItem::Render(const HDC hdc, const RECT *rc, bool fIgnoreGlyph) const { BYTE l = m_bLeft, r = m_bRight, t = m_bTop, b = m_bBottom; LONG width = rc->right - rc->left; LONG height = rc->bottom - rc->top; BOOL isGlyph = ((m_dwFlags & IMAGE_GLYPH) && Skin->haveGlyphItem()); BOOL fCleanUp = TRUE; HDC hdcSrc = 0; HBITMAP hbmOld; LONG srcOrigX = isGlyph ? m_glyphMetrics[0] : 0; LONG srcOrigY = isGlyph ? m_glyphMetrics[1] : 0; if (m_hdc == 0) { hdcSrc = CreateCompatibleDC(hdc); hbmOld = (HBITMAP)SelectObject(hdcSrc, isGlyph ? Skin->getGlyphItem()->getHbm() : m_hbm); } else { if (fIgnoreGlyph) hdcSrc = m_hdc; else hdcSrc = isGlyph ? Skin->getGlyphItem()->getDC() : m_hdc; fCleanUp = FALSE; } if (m_dwFlags & IMAGE_FLAG_DIVIDED) { // top 3 items GdiAlphaBlend(hdc, rc->left, rc->top, l, t, hdcSrc, srcOrigX, srcOrigY, l, t, m_bf); GdiAlphaBlend(hdc, rc->left + l, rc->top, width - l - r, t, hdcSrc, srcOrigX + l, srcOrigY, m_inner_width, t, m_bf); GdiAlphaBlend(hdc, rc->right - r, rc->top, r, t, hdcSrc, srcOrigX + (m_width - r), srcOrigY, r, t, m_bf); // middle 3 items GdiAlphaBlend(hdc, rc->left, rc->top + t, l, height - t - b, hdcSrc, srcOrigX, srcOrigY + t, l, m_inner_height, m_bf); if ((m_dwFlags & IMAGE_FILLSOLID) && m_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, m_fillBrush); } else GdiAlphaBlend(hdc, rc->left + l, rc->top + t, width - l - r, height - t - b, hdcSrc, srcOrigX + l, srcOrigY + t, m_inner_width, m_inner_height, m_bf); GdiAlphaBlend(hdc, rc->right - r, rc->top + t, r, height - t - b, hdcSrc, srcOrigX + (m_width - r), srcOrigY + t, r, m_inner_height, m_bf); // bottom 3 items GdiAlphaBlend(hdc, rc->left, rc->bottom - b, l, b, hdcSrc, srcOrigX, srcOrigY + (m_height - b), l, b, m_bf); GdiAlphaBlend(hdc, rc->left + l, rc->bottom - b, width - l - r, b, hdcSrc, srcOrigX + l, srcOrigY + (m_height - b), m_inner_width, b, m_bf); GdiAlphaBlend(hdc, rc->right - r, rc->bottom - b, r, b, hdcSrc, srcOrigX + (m_width - r), srcOrigY + (m_height - b), r, b, m_bf); } else switch (m_bStretch) { case IMAGE_STRETCH_H: // tile image vertically, stretch to width { LONG top = rc->top; do { if (top + m_height <= rc->bottom) { GdiAlphaBlend(hdc, rc->left, top, width, m_height, hdcSrc, srcOrigX, srcOrigY, m_width, m_height, m_bf); top += m_height; } else { GdiAlphaBlend(hdc, rc->left, top, width, rc->bottom - top, hdcSrc, srcOrigX, srcOrigY, m_width, rc->bottom - top, m_bf); break; } } while (true); break; } case IMAGE_STRETCH_V: // tile horizontally, stretch to height { LONG left = rc->left; do { if (left + m_width <= rc->right) { GdiAlphaBlend(hdc, left, rc->top, m_width, height, hdcSrc, srcOrigX, srcOrigY, m_width, m_height, m_bf); left += m_width; } else { GdiAlphaBlend(hdc, left, rc->top, rc->right - left, height, hdcSrc, srcOrigX, srcOrigY, rc->right - left, m_height, m_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, m_width, m_height, m_bf); break; } if (fCleanUp) { SelectObject(hdcSrc, hbmOld); DeleteDC(hdcSrc); } } static CSkinItem StatusItem_Default = { _T("Container"), "EXBK_Offline", ID_EXTBKCONTAINER, CLCDEFAULT_GRADIENT, CLCDEFAULT_CORNER, CLCDEFAULT_COLOR, CLCDEFAULT_COLOR2, CLCDEFAULT_COLOR2_TRANSPARENT, CLCDEFAULT_TEXTCOLOR, CLCDEFAULT_ALPHA, CLCDEFAULT_MRGN_LEFT, CLCDEFAULT_MRGN_TOP, CLCDEFAULT_MRGN_RIGHT, CLCDEFAULT_MRGN_BOTTOM, CLCDEFAULT_IGNORE }; static struct { TCHAR *szIniKey, *szIniName; char *szSetting; unsigned int size; int defaultval; } _tagSettings[] = { _T("Global"), _T("SbarHeight"), "S_sbarheight", 1, 22, _T("ClientArea"), _T("Left"), "S_tborder_outer_left", 1, 0, _T("ClientArea"), _T("Right"), "S_tborder_outer_right", 1, 0, _T("ClientArea"), _T("Top"), "S_tborder_outer_top", 1, 0, _T("ClientArea"), _T("Bottom"), "S_tborder_outer_bottom", 1, 0, _T("ClientArea"), _T("Inner"), "S_tborder", 1, 0, _T("Global"), _T("TabTextNormal"), "S_tab_txt_normal", 5, 0, _T("Global"), _T("TabTextActive"), "S_tab_txt_active", 5, 0, _T("Global"), _T("TabTextUnread"), "S_tab_txt_unread", 5, 0, _T("Global"), _T("TabTextHottrack"), "S_tab_txt_hottrack", 5, 0, NULL, NULL, NULL, 0, 0 }; void CImageItem::Create(const TCHAR *szImageFile) { HBITMAP hbm = LoadPNG(szImageFile); BITMAP bm; m_hdc = 0; m_hbmOld = 0; m_hbm = 0; if (hbm) { m_hbm = hbm; m_bf.BlendFlags = 0; m_bf.BlendOp = AC_SRC_OVER; m_bf.AlphaFormat = 0; GetObject(hbm, sizeof(bm), &bm); if (bm.bmBitsPixel == 32 && m_dwFlags & IMAGE_PERPIXEL_ALPHA) { CImageItem::PreMultiply(m_hbm, 1); m_bf.AlphaFormat = AC_SRC_ALPHA; } m_width = bm.bmWidth; m_height = bm.bmHeight; m_inner_height = m_height - m_bTop - m_bBottom; m_inner_width = m_width - m_bLeft - m_bRight; if (m_bTop && m_bBottom && m_bLeft && m_bRight) { m_dwFlags |= IMAGE_FLAG_DIVIDED; if (m_inner_height <= 0 || m_inner_width <= 0) { DeleteObject(hbm); m_hbm = 0; return; } } } } /** * Reads the definitions for an image item from the given .tsk file * It does _not_ create the image itself, a call to CImageItem::Create() must be done * to read the image in memory and prepare * * @param szFilename char*: full path and filename to the .TSK file * * @return char*: full path and filename to the .png image which represents this image item. * caller MUST delete it. */ TCHAR* CImageItem::Read(const TCHAR *szFilename) { TCHAR buffer[501]; TCHAR szDrive[MAX_PATH], szPath[MAX_PATH]; TCHAR *szFinalName = 0; GetPrivateProfileString(m_szName, _T("Glyph"), _T("None"), buffer, 500, szFilename); if (_tcscmp(buffer, _T("None"))) { _stscanf(buffer, _T("%d,%d,%d,%d"), &m_glyphMetrics[0], &m_glyphMetrics[1], &m_glyphMetrics[2], &m_glyphMetrics[3]); if (m_glyphMetrics[2] > m_glyphMetrics[0] && m_glyphMetrics[3] > m_glyphMetrics[1]) { m_dwFlags |= IMAGE_GLYPH; m_glyphMetrics[2] = (m_glyphMetrics[2] - m_glyphMetrics[0]) + 1; m_glyphMetrics[3] = (m_glyphMetrics[3] - m_glyphMetrics[1]) + 1; } } GetPrivateProfileString(m_szName, _T("Image"), _T("None"), buffer, 500, szFilename); if (_tcscmp(buffer, _T("None")) || m_dwFlags & IMAGE_GLYPH) { szFinalName = new TCHAR[MAX_PATH]; //strncpy(m_szName, &m_szName[1], sizeof(m_szName)); //m_szName[sizeof(m_szName) - 1] = 0; _tsplitpath(szFilename, szDrive, szPath, NULL, NULL); mir_sntprintf(szFinalName, MAX_PATH, _T("%s\\%s%s"), szDrive, szPath, buffer); if (!PathFileExists(szFinalName)) { delete[] szFinalName; szFinalName = 0; } m_alpha = GetPrivateProfileInt(m_szName, _T("Alpha"), 100, szFilename); m_alpha = min(m_alpha, 100); m_alpha = (BYTE)((FLOAT)(((FLOAT) m_alpha) / 100) * 255); m_bf.SourceConstantAlpha = m_alpha; m_bLeft = GetPrivateProfileInt(m_szName, _T("Left"), 0, szFilename); m_bRight = GetPrivateProfileInt(m_szName, _T("Right"), 0, szFilename); m_bTop = GetPrivateProfileInt(m_szName, _T("Top"), 0, szFilename); m_bBottom = GetPrivateProfileInt(m_szName, _T("Bottom"), 0, szFilename); if (m_dwFlags & IMAGE_GLYPH) { m_width = m_glyphMetrics[2]; m_height = m_glyphMetrics[3]; m_inner_height = m_glyphMetrics[3] - m_bTop - m_bBottom; m_inner_width = m_glyphMetrics[2] - m_bRight - m_bLeft; if (m_bTop && m_bBottom && m_bLeft && m_bRight) m_dwFlags |= IMAGE_FLAG_DIVIDED; m_bf.BlendFlags = 0; m_bf.BlendOp = AC_SRC_OVER; m_bf.AlphaFormat = 0; m_dwFlags |= IMAGE_PERPIXEL_ALPHA; m_bf.AlphaFormat = AC_SRC_ALPHA; if (m_inner_height <= 0 || m_inner_width <= 0) { if (szFinalName) { delete[] szFinalName; szFinalName = 0; } return(szFinalName); } } GetPrivateProfileString(m_szName, _T("Fillcolor"), _T("None"), buffer, 500, szFilename); if (_tcscmp(buffer, _T("None"))) { COLORREF fillColor = CSkin::HexStringToLong(buffer); m_fillBrush = CreateSolidBrush(fillColor); m_dwFlags |= IMAGE_FILLSOLID; } else m_fillBrush = 0; GetPrivateProfileString(m_szName, _T("Colorkey"), _T("None"), buffer, 500, szFilename); if (_tcscmp(buffer, _T("None"))) { CSkin::m_ContainerColorKey = CSkin::HexStringToLong(buffer); if (CSkin::m_ContainerColorKeyBrush) DeleteObject(CSkin::m_ContainerColorKeyBrush); CSkin::m_ContainerColorKeyBrush = CreateSolidBrush(CSkin::m_ContainerColorKey); } GetPrivateProfileString(m_szName, _T("Stretch"), _T("None"), buffer, 500, szFilename); if (buffer[0] == 'B' || buffer[0] == 'b') m_bStretch = IMAGE_STRETCH_B; else if (buffer[0] == 'h' || buffer[0] == 'H') m_bStretch = IMAGE_STRETCH_V; else if (buffer[0] == 'w' || buffer[0] == 'W') m_bStretch = IMAGE_STRETCH_H; m_hbm = 0; if (GetPrivateProfileInt(m_szName, _T("Perpixel"), 0, szFilename)) m_dwFlags |= IMAGE_PERPIXEL_ALPHA; return(szFinalName); } return 0; } /** * Free all resources allocated by an image item */ void CImageItem::Free() { if (m_hdc ) { ::SelectObject(m_hdc, m_hbmOld); ::DeleteDC(m_hdc); } if (m_hbm) ::DeleteObject(m_hbm); if (m_fillBrush) ::DeleteObject(m_fillBrush); ZeroMemory(this, sizeof(CImageItem)); } /** * Set the alpha value for a 32bit RGBA bitmap to the given value * * @param hBitmap bitmap handle * @param bAlpha new alpha value (0 -> fully transparent, 255 -> opaque) * default value is 255 */ void CImageItem::SetBitmap32Alpha(HBITMAP hBitmap, BYTE bAlpha) { BITMAP bmp; int x, y; BOOL fixIt = TRUE; GetObject(hBitmap, sizeof(bmp), &bmp); if (bmp.bmBitsPixel != 32) return; DWORD dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8); BYTE *p = (BYTE *)mir_alloc(dwLen); if (p == NULL) return; memset(p, 0, dwLen); GetBitmapBits(hBitmap, dwLen, p); for (y = 0; y < bmp.bmHeight; ++y) { BYTE *px = p + bmp.bmWidth * 4 * y; for (x = 0; x < bmp.bmWidth; ++x) { px[3] = bAlpha; px += 4; } } SetBitmapBits(hBitmap, bmp.bmWidth * bmp.bmHeight * 4, p); mir_free(p); } void CImageItem::PreMultiply(HBITMAP hBitmap, int mode) { BITMAP bmp; ::GetObject(hBitmap, sizeof(bmp), &bmp); int width = bmp.bmWidth; int height = bmp.bmHeight; DWORD dwLen = width * height * 4; BYTE *p = (BYTE *)mir_alloc(dwLen); if (p) { ::GetBitmapBits(hBitmap, dwLen, p); for (int y = 0; y < height; ++y) { BYTE *px = p + width * 4 * y; for (int x = 0; x < width; ++x) { if (mode) { BYTE alpha = px[3]; px[0] = px[0] * alpha / 255; px[1] = px[1] * alpha / 255; px[2] = px[2] * alpha / 255; } else px[3] = 255; px += 4; } } dwLen = ::SetBitmapBits(hBitmap, dwLen, p); mir_free(p); } } void CImageItem::Colorize(HBITMAP hBitmap, BYTE dr, BYTE dg, BYTE db, BYTE alpha) { BYTE *p = NULL; DWORD dwLen; int width, height, x, y; BITMAP bmp; float r = (float)dr / 2.55; float g = (float)dg / 2.55; float b = (float)db / 2.55; ::GetObject(hBitmap, sizeof(bmp), &bmp); width = bmp.bmWidth; height = bmp.bmHeight; dwLen = width * height * 4; p = (BYTE *)mir_alloc(dwLen); if (p) { ::GetBitmapBits(hBitmap, dwLen, p); for (y = 0; y < height; ++y) { BYTE *px = p + width * 4 * y; for (x = 0; x < width; ++x) { px[0] = (int)(px[0] + b) > 255 ? 255 : px[0] + b; px[1] = (int)(px[1] + g) > 255 ? 255 : px[1] + g; px[2] = (int)(px[2] + r) > 255 ? 255 : px[2] + r; px[3] += alpha; px += 4; } } dwLen = ::SetBitmapBits(hBitmap, dwLen, p); mir_free(p); } } /** * load PNG image using core service (advaimg) */ HBITMAP TSAPI CImageItem::LoadPNG(const TCHAR *szFilename) { HBITMAP hBitmap = 0; hBitmap = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)szFilename, IMGL_TCHAR); return hBitmap; } /** * set filename and load parameters from the database * called on: * ) init * ) manual loading on user's request */ void CSkin::setFileName() { DBVARIANT dbv; if (0 == db_get_ts(0, SRMSGMOD_T, "ContainerSkin", &dbv)) { M.pathToAbsolute(dbv.ptszVal, m_tszFileName, M.getSkinPath()); m_tszFileName[MAX_PATH - 1] = 0; db_free(&dbv); } else m_tszFileName[0] = 0; m_fLoadOnStartup = M.GetByte("useskin", 0) ? true : false; } /** * initialize the skin object */ void CSkin::Init(bool fStartup) { m_ImageItems = 0; m_SkinItems = ::SkinItems; m_fLoadOnStartup = false; m_skinEnabled = m_frameSkins = false; m_bAvatarBorderType = AVBORDER_NORMAL; m_avatarBorderClr = ::GetSysColor(COLOR_3DDKSHADOW); m_sideBarContainerBG = ::GetSysColor(COLOR_3DFACE); m_SkinItems[ID_EXTBKINFOPANELBG] = _defInfoPanel; /* * read current skin name from db */ m_DisableScrollbars = M.GetByte("disableVScroll", 0) ? true : false; setFileName(); m_aeroEffect = M.GetDword("aerostyle", AERO_EFFECT_MILK); if (m_fLoadOnStartup && fStartup) Load(); } /** * throws a warning to close all message windows before a skin can * be loaded. user can cancel it * @return: bool: true if windows were closed (or none was open) -> skin can be loaded * */ bool CSkin::warnToClose() const { if (::pFirstContainer == NULL) return true; if (MessageBox(0, TranslateT("All message containers need to close before the skin can be changed\nProceed?"), TranslateT("Change skin"), MB_YESNO | MB_ICONQUESTION) != IDYES) return false; TContainerData *pContainer = ::pFirstContainer; while (pFirstContainer) SendMessage(pFirstContainer->hwnd, WM_CLOSE, 0, 1); return true; } /** * mir_free the aero tab bitmaps * only called on exit, NOT when a skin is unloaded as these elements * are always needed (even without a skin) */ void CSkin::UnloadAeroTabs() { if (m_tabTop) { delete m_tabTop; m_tabTop = NULL; } if (m_tabBottom) { delete m_tabBottom; m_tabBottom = NULL; } if (m_tabGlowTop) { delete m_tabGlowTop; m_tabGlowTop = NULL; } if (m_tabGlowBottom) { delete m_tabGlowBottom; m_tabGlowTop = NULL; } if (m_switchBarItem) { delete m_switchBarItem; m_switchBarItem = NULL; } } /** * Unload the skin. Free everything allocated. * Called when: * * user unloads the skin from the dialog box * * a new skin is loaded by user's request. */ void CSkin::Unload() { // do nothing when user decides to not close any window if (warnToClose() == false) return; /* * delete all image items */ m_skinEnabled = m_frameSkins = false; CImageItem *tmp = m_ImageItems, *nextItem; while(tmp) { nextItem = tmp->getNextItem(); delete tmp; tmp = nextItem; } m_ImageItems = 0; m_glyphItem.Free(); if (m_ContainerColorKeyBrush) ::DeleteObject(m_ContainerColorKeyBrush); if (m_MenuBGBrush) ::DeleteObject(m_MenuBGBrush); if (m_BrushBack) ::DeleteObject(m_BrushBack); m_ContainerColorKeyBrush = m_MenuBGBrush = 0; if (m_SkinLightShadowPen) ::DeleteObject(m_SkinLightShadowPen); m_SkinLightShadowPen = 0; if (m_SkinDarkShadowPen) ::DeleteObject(m_SkinDarkShadowPen); m_SkinDarkShadowPen = 0; if (m_SkinItems) { for (int i=0; i < ID_EXTBK_LAST; i++) { m_SkinItems[i].IGNORED = 1; m_SkinItems[i].imageItem = 0; } m_SkinItems[ID_EXTBKINFOPANELBG] = _defInfoPanel; } ZeroMemory(this, sizeof(CSkin)); m_SkinItems = ::SkinItems; setFileName(); m_bClipBorder = m_DisableScrollbars = false; m_SkinnedFrame_left = m_SkinnedFrame_right = m_SkinnedFrame_bottom = m_SkinnedFrame_caption = 0; m_realSkinnedFrame_left = m_realSkinnedFrame_right = m_realSkinnedFrame_bottom = m_realSkinnedFrame_caption = 0; m_titleBarLeftOff = m_titleButtonTopOff = m_captionOffset = m_captionPadding = m_titleBarRightOff = m_sidebarTopOffset = m_sidebarBottomOffset = m_bRoundedCorner = 0; m_titleBarButtonSize.cx = m_titleBarButtonSize.cy = 0; m_ContainerColorKey = 0; m_ContainerColorKeyBrush = m_MenuBGBrush = 0; m_skinEnabled = m_frameSkins = false; if (m_closeIcon) ::DestroyIcon(m_closeIcon); if (m_maxIcon) ::DestroyIcon(m_maxIcon); if (m_minIcon) ::DestroyIcon(m_minIcon); m_closeIcon = m_maxIcon = m_minIcon = 0; for (int i=0; i < m_nrSkinIcons; i++) if (m_skinIcons[i].phIcon ) ::DestroyIcon(*(m_skinIcons[i].phIcon)); mir_free(m_skinIcons); M.getAeroState(); // refresh after unload ::FreeTabConfig(); ::ReloadTabConfig(); m_bAvatarBorderType = AVBORDER_NORMAL; m_avatarBorderClr = ::GetSysColor(COLOR_3DDKSHADOW); m_sideBarContainerBG = ::GetSysColor(COLOR_3DFACE); m_DisableScrollbars = M.GetByte("disableVScroll", 0) ? true : false; } void CSkin::LoadIcon(const TCHAR *szSection, const TCHAR *name, HICON *hIcon) { TCHAR buffer[512]; if (*hIcon != 0) DestroyIcon(*hIcon); GetPrivateProfileString(szSection, name, _T("none"), buffer, 250, m_tszFileName); buffer[500] = 0; if (_tcsicmp(buffer, _T("none"))) { TCHAR szDrive[MAX_PATH], szDir[MAX_PATH], szImagePath[MAX_PATH]; _tsplitpath(m_tszFileName, szDrive, szDir, NULL, NULL); mir_sntprintf(szImagePath, MAX_PATH, _T("%s\\%s\\%s"), szDrive, szDir, buffer); if (hIcon) *hIcon = (HICON)LoadImage(0, szImagePath, IMAGE_ICON, 16, 16, LR_LOADFROMFILE); } } /** * Read a skin item (not a image item - these are handled elsewhere) * Reads all values from the .ini style .tsk file and fills the * structure. * * @param id int: zero-based index into the table of predefined skin items * @param szItem char *: the section name in the ini file which holds the definition for this * item. */ void CSkin::ReadItem(const int id, const TCHAR *szItem) { TCHAR buffer[512]; TCHAR def_color[20]; COLORREF clr; CSkinItem *defaults = &StatusItem_Default; CSkinItem *this_item = &m_SkinItems[id]; this_item->ALPHA = (int)GetPrivateProfileInt(szItem, _T("Alpha"), defaults->ALPHA, m_tszFileName); this_item->ALPHA = min(this_item->ALPHA, 100); clr = RGB(GetBValue(defaults->COLOR), GetGValue(defaults->COLOR), GetRValue(defaults->COLOR)); mir_sntprintf(def_color, 15, _T("%6.6x"), clr); GetPrivateProfileString(szItem, _T("Color1"), def_color, buffer, 400, m_tszFileName); this_item->COLOR = HexStringToLong(buffer); clr = RGB(GetBValue(defaults->COLOR2), GetGValue(defaults->COLOR2), GetRValue(defaults->COLOR2)); mir_sntprintf(def_color, 15, _T("%6.6x"), clr); GetPrivateProfileString(szItem, _T("Color2"), def_color, buffer, 400, m_tszFileName); this_item->COLOR2 = HexStringToLong(buffer); this_item->COLOR2_TRANSPARENT = (BYTE)GetPrivateProfileInt(szItem, _T("COLOR2_TRANSPARENT"), defaults->COLOR2_TRANSPARENT, m_tszFileName); this_item->CORNER = defaults->CORNER & CORNER_ACTIVE ? defaults->CORNER : 0; GetPrivateProfileString(szItem, _T("Corner"), _T("None"), buffer, 400, m_tszFileName); if (_tcsstr(buffer, _T("tl"))) this_item->CORNER |= CORNER_TL; if (_tcsstr(buffer, _T("tr"))) this_item->CORNER |= CORNER_TR; if (_tcsstr(buffer, _T("bl"))) this_item->CORNER |= CORNER_BL; if (_tcsstr(buffer, _T("br"))) this_item->CORNER |= CORNER_BR; if (this_item->CORNER) this_item->CORNER |= CORNER_ACTIVE; this_item->GRADIENT = defaults->GRADIENT & GRADIENT_ACTIVE ? defaults->GRADIENT : 0; GetPrivateProfileString(szItem, _T("Gradient"), _T("None"), buffer, 400, m_tszFileName); if (_tcsstr(buffer, _T("left"))) this_item->GRADIENT = GRADIENT_RL; else if (_tcsstr(buffer, _T("right"))) this_item->GRADIENT = GRADIENT_LR; else if (_tcsstr(buffer, _T("up"))) this_item->GRADIENT = GRADIENT_BT; else if (_tcsstr(buffer, _T("down"))) this_item->GRADIENT = GRADIENT_TB; if (this_item->GRADIENT) this_item->GRADIENT |= GRADIENT_ACTIVE; this_item->MARGIN_LEFT = GetPrivateProfileInt(szItem, _T("Left"), defaults->MARGIN_LEFT, m_tszFileName); this_item->MARGIN_RIGHT = GetPrivateProfileInt(szItem, _T("Right"), defaults->MARGIN_RIGHT, m_tszFileName); this_item->MARGIN_TOP = GetPrivateProfileInt(szItem, _T("Top"), defaults->MARGIN_TOP, m_tszFileName); this_item->MARGIN_BOTTOM = GetPrivateProfileInt(szItem, _T("Bottom"), defaults->MARGIN_BOTTOM, m_tszFileName); this_item->BORDERSTYLE = GetPrivateProfileInt(szItem, _T("Radius"), defaults->BORDERSTYLE, m_tszFileName); GetPrivateProfileString(szItem, _T("Textcolor"), _T("ffffffff"), buffer, 400, m_tszFileName); this_item->TEXTCOLOR = HexStringToLong(buffer); this_item->IGNORED = 0; } /** * stub to read a single item. Called from CSkin::LoadItems() * The real work is done by the CImageItem::Read(). * * @param itemname char *: image item name, also section name in the .tsk file */ void CSkin::ReadImageItem(const TCHAR *itemname) { TCHAR buffer[512], szItemNr[30]; CImageItem tmpItem(itemname); TCHAR *szImageFileName = tmpItem.Read(m_tszFileName); if (!_tcsicmp(itemname, _T("$glyphs")) && szImageFileName != 0) { // the glyph item MUST have a valid image tmpItem.Create(szImageFileName); if (tmpItem.getHbm()) { m_glyphItem = tmpItem; m_fHaveGlyph = true; } tmpItem.Clear(); delete[] szImageFileName; return; } /* * handle the assignments of image items to skin items */ for (int n = 0;;n++) { mir_sntprintf(szItemNr, 30, _T("Item%d"), n); GetPrivateProfileString(itemname, szItemNr, _T("None"), buffer, 500, m_tszFileName); if (!_tcscmp(buffer, _T("None"))) break; for (int i=0; i <= ID_EXTBK_LAST; i++) { if (!_tcsicmp(SkinItems[i].szName[0] == '{' ? &SkinItems[i].szName[3] : SkinItems[i].szName, buffer)) { if (!(tmpItem.getFlags() & IMAGE_GLYPH)) { if (szImageFileName) tmpItem.Create(szImageFileName); else { tmpItem.Clear(); return; // no reference to the glpyh image and no valid image file name -> invalid item } } if (tmpItem.getHbm() || (tmpItem.getFlags() & IMAGE_GLYPH)) { CImageItem *newItem = new CImageItem(tmpItem); SkinItems[i].imageItem = newItem; if (m_ImageItems == NULL) m_ImageItems = newItem; else { CImageItem *pItem = m_ImageItems; while (pItem->getNextItem() != 0) pItem = pItem->getNextItem(); pItem->setNextItem(newItem); } } } } } tmpItem.Clear(); if (szImageFileName) delete[] szImageFileName; } /** * Load the skin from the .tsk file * It reads and initializes all static values for the skin. Afterwards * it calls ReadItems() to read additional skin information like image items, * buttons and icons. */ void CSkin::Load(void) { if (warnToClose() == false) return; if (m_skinEnabled) { Unload(); m_skinEnabled = false; } m_fHaveGlyph = false; if ( !m_tszFileName[0] || !::PathFileExists(m_tszFileName)) return; TCHAR *p; TCHAR *szSections = (TCHAR*)mir_alloc(6004); int i = 1, j = 0; UINT data; TCHAR buffer[500]; if (!(GetPrivateProfileInt(_T("Global"), _T("Version"), 0, m_tszFileName) >= 1 && GetPrivateProfileInt(_T("Global"), _T("Signature"), 0, m_tszFileName) == 101)) return; i = 0; while (_tagSettings[i].szIniKey != NULL) { data = 0; data = GetPrivateProfileInt(_tagSettings[i].szIniKey, _tagSettings[i].szIniName, _tagSettings[i].defaultval, m_tszFileName); switch (_tagSettings[i].size) { case 1: db_set_b(0, SRMSGMOD_T, _tagSettings[i].szSetting, (BYTE)data); break; case 4: db_set_dw(0, SRMSGMOD_T, _tagSettings[i].szSetting, data); break; case 2: db_set_w(NULL, SRMSGMOD_T, _tagSettings[i].szSetting, (WORD)data); break; case 5: GetPrivateProfileString(_tagSettings[i].szIniKey, _tagSettings[i].szIniName, _T("000000"), buffer, 10, m_tszFileName); db_set_dw(0, SRMSGMOD_T, _tagSettings[i].szSetting, HexStringToLong(buffer)); break; } i++; } m_DisableScrollbars = M.GetByte("disableVScroll", 0) ? true : false; ZeroMemory(szSections, 6000); p = szSections; GetPrivateProfileSectionNames(szSections, 3000, m_tszFileName); szSections[3001] = szSections[3000] = 0; p = szSections; while (lstrlen(p) > 1) { if (p[0] != '%') { p += (lstrlen(p) + 1); continue; } for (i=0; i <= ID_EXTBK_LAST; i++) { if (!_tcsicmp(&p[1], SkinItems[i].szName[0] == '{' ? &SkinItems[i].szName[3] : SkinItems[i].szName)) { ReadItem(i, p); break; } } p += (lstrlen(p) + 1); j++; } if (j > 0) { m_skinEnabled = true; M.getAeroState(); // refresh aero state (set to false when a skin is successfully loaded and active) } GetPrivateProfileString(_T("Avatars"), _T("BorderColor"), _T("000000"), buffer, 20, m_tszFileName); m_avatarBorderClr = (COLORREF)HexStringToLong(buffer); GetPrivateProfileString(_T("Global"), _T("SideBarBG"), _T("None"), buffer, 20, m_tszFileName); if (_tcscmp(buffer, _T("None"))) m_sideBarContainerBG = (COLORREF)HexStringToLong(buffer); else m_sideBarContainerBG = SkinItems[ID_EXTBKSIDEBARBG].COLOR; m_bAvatarBorderType = GetPrivateProfileInt(_T("Avatars"), _T("BorderType"), 1, m_tszFileName); LoadIcon(_T("Global"), _T("CloseGlyph"), &CSkin::m_closeIcon); LoadIcon(_T("Global"), _T("MaximizeGlyph"), &CSkin::m_maxIcon); LoadIcon(_T("Global"), _T("MinimizeGlyph"), &CSkin::m_minIcon); m_frameSkins = GetPrivateProfileInt(_T("Global"), _T("framelessmode"), 0, m_tszFileName) ? true : false; m_DisableScrollbars = GetPrivateProfileInt(_T("Global"), _T("NoScrollbars"), 0, m_tszFileName) ? true : false; m_SkinnedFrame_left = GetPrivateProfileInt(_T("WindowFrame"), _T("left"), 4, m_tszFileName); m_SkinnedFrame_right = GetPrivateProfileInt(_T("WindowFrame"), _T("right"), 4, m_tszFileName); m_SkinnedFrame_caption = GetPrivateProfileInt(_T("WindowFrame"), _T("Caption"), 24, m_tszFileName); m_SkinnedFrame_bottom = GetPrivateProfileInt(_T("WindowFrame"), _T("bottom"), 4, m_tszFileName); m_titleBarButtonSize.cx = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleButtonWidth"), 24, m_tszFileName); m_titleBarButtonSize.cy = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleButtonHeight"), 12, m_tszFileName); m_titleButtonTopOff = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleButtonTopOffset"), 0, m_tszFileName); m_titleBarRightOff = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleBarRightOffset"), 0, m_tszFileName); m_titleBarLeftOff = GetPrivateProfileInt(_T("WindowFrame"), _T("TitleBarLeftOffset"), 0, m_tszFileName); m_captionOffset = GetPrivateProfileInt(_T("WindowFrame"), _T("CaptionOffset"), 3, m_tszFileName); m_captionPadding = GetPrivateProfileInt(_T("WindowFrame"), _T("CaptionPadding"), 0, m_tszFileName); m_sidebarTopOffset = GetPrivateProfileInt(_T("ClientArea"), _T("SidebarTop"), -1, m_tszFileName); m_sidebarBottomOffset = GetPrivateProfileInt(_T("ClientArea"), _T("SidebarBottom"), -1, m_tszFileName); m_bClipBorder = GetPrivateProfileInt(_T("WindowFrame"), _T("ClipFrame"), 0, m_tszFileName) ? true : false; BYTE radius_tl, radius_tr, radius_bl, radius_br; TCHAR szFinalName[MAX_PATH]; TCHAR szDrive[MAX_PATH], szPath[MAX_PATH]; radius_tl = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusTL"), 0, m_tszFileName); radius_tr = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusTR"), 0, m_tszFileName); radius_bl = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusBL"), 0, m_tszFileName); radius_br = GetPrivateProfileInt(_T("WindowFrame"), _T("RadiusBR"), 0, m_tszFileName); CSkin::m_bRoundedCorner = radius_tl; GetPrivateProfileString(_T("Theme"), _T("File"), _T("None"), buffer, MAX_PATH, m_tszFileName); _tsplitpath(m_tszFileName, szDrive, szPath, NULL, NULL); mir_sntprintf(szFinalName, MAX_PATH, _T("%s\\%s\\%s"), szDrive, szPath, buffer); if (PathFileExists(szFinalName)) { ReadThemeFromINI(szFinalName, 0, FALSE, m_fLoadOnStartup ? 0 : M.GetByte("skin_loadmode", 0)); CacheLogFonts(); CacheMsgLogIcons(); } GetPrivateProfileString(_T("Global"), _T("MenuBarBG"), _T("None"), buffer, 20, m_tszFileName); data = HexStringToLong(buffer); if (m_MenuBGBrush) { DeleteObject(m_MenuBGBrush); m_MenuBGBrush = 0; } if (_tcscmp(buffer, _T("None"))) m_MenuBGBrush = CreateSolidBrush(data); GetPrivateProfileString(_T("Global"), _T("LightShadow"), _T("000000"), buffer, 20, m_tszFileName); data = HexStringToLong(buffer); CSkin::m_SkinLightShadowPen = CreatePen(PS_SOLID, 1, RGB(GetRValue(data), GetGValue(data), GetBValue(data))); GetPrivateProfileString(_T("Global"), _T("DarkShadow"), _T("000000"), buffer, 20, m_tszFileName); data = HexStringToLong(buffer); CSkin::m_SkinDarkShadowPen = CreatePen(PS_SOLID, 1, RGB(GetRValue(data), GetGValue(data), GetBValue(data))); SkinCalcFrameWidth(); GetPrivateProfileString(_T("Global"), _T("FontColor"), _T("None"), buffer, 20, m_tszFileName); if (_tcscmp(buffer, _T("None"))) CSkin::m_DefaultFontColor = HexStringToLong(buffer); else CSkin::m_DefaultFontColor = GetSysColor(COLOR_BTNTEXT); buffer[499] = 0; mir_free(szSections); LoadItems(); ::FreeTabConfig(); ::ReloadTabConfig(); } #define SECT_BUFFER_SIZE 2500 /** * Load additional skin items (like image items, buttons, icons etc.) * This is called AFTER ReadItems() has read the basic skin items */ void CSkin::LoadItems() { TCHAR *szSections = NULL; TCHAR *p, *p1; TIconDesc tmpIconDesc = {0}; CImageItem *pItem = m_ImageItems; if (m_skinIcons == NULL) m_skinIcons = (TIconDescW *)mir_calloc(sizeof(TIconDescW) * NR_MAXSKINICONS); m_nrSkinIcons = 0; szSections = (TCHAR*)mir_alloc((SECT_BUFFER_SIZE + 2) * sizeof(TCHAR)); ZeroMemory(szSections, (SECT_BUFFER_SIZE + 2) * sizeof(TCHAR)); GetPrivateProfileSection(_T("Icons"), szSections, SECT_BUFFER_SIZE, m_tszFileName); szSections[SECT_BUFFER_SIZE] = 0; p = szSections; while (lstrlen(p) > 1) { p1 = _tcschr(p, (int)'='); if (p1) *p1 = 0; if (m_nrSkinIcons < NR_MAXSKINICONS && p1) { LoadIcon(_T("Icons"), p, (HICON *)&tmpIconDesc.uId); if (tmpIconDesc.uId) { ZeroMemory(&m_skinIcons[m_nrSkinIcons], sizeof(TIconDesc)); m_skinIcons[m_nrSkinIcons].uId = tmpIconDesc.uId; m_skinIcons[m_nrSkinIcons].phIcon = (HICON *)(&m_skinIcons[m_nrSkinIcons].uId); m_skinIcons[m_nrSkinIcons].szName = (TCHAR*)mir_alloc(sizeof(TCHAR) * (lstrlen(p) + 1)); lstrcpy(m_skinIcons[m_nrSkinIcons].szName, p); m_nrSkinIcons++; } } if (p1) *p1 = '='; p += (lstrlen(p) + 1); } ZeroMemory(szSections, (SECT_BUFFER_SIZE + 2) * sizeof(TCHAR)); GetPrivateProfileSectionNames(szSections, SECT_BUFFER_SIZE, m_tszFileName); szSections[SECT_BUFFER_SIZE] = 0; p = szSections; while (lstrlen(p) > 1) { if (p[0] == '$') ReadImageItem(p); p += (lstrlen(p) + 1); } nextButtonID = IDC_TBFIRSTUID; p = szSections; /* while (lstrlen(p) > 1) { if (p[0] == '!') ReadButtonItem(p); p += (lstrlen(p) + 1); } */ mir_free(szSections); g_ButtonSet.top = GetPrivateProfileInt(_T("ButtonArea"), _T("top"), 0, m_tszFileName); g_ButtonSet.bottom = GetPrivateProfileInt(_T("ButtonArea"), _T("bottom"), 0, m_tszFileName); g_ButtonSet.left = GetPrivateProfileInt(_T("ButtonArea"), _T("left"), 0, m_tszFileName); g_ButtonSet.right = GetPrivateProfileInt(_T("ButtonArea"), _T("right"), 0, m_tszFileName); } /** * setup and cache the bitmap for the close button on tabs and switch bar * buttons. * re-created when: * ) theme changes * ) icons change (via ico lib service) * * @param fDeleteOnly: only delete GDI resources (this is ONLY used at plugin shutdown) */ void CSkin::setupTabCloseBitmap(bool fDeleteOnly) { if (m_tabCloseHDC || fDeleteOnly) { if (m_tabCloseHDC) { ::SelectObject(m_tabCloseHDC, m_tabCloseOldBitmap); ::DeleteObject(m_tabCloseBitmap); ::DeleteDC(m_tabCloseHDC); } if (fDeleteOnly) return; } bool fFree = false; RECT rc = {0, 0, 20, 20}; HDC dc = ::GetDC(PluginConfig.g_hwndHotkeyHandler); m_tabCloseHDC = ::CreateCompatibleDC(dc); if (M.isAero()) m_tabCloseBitmap = CreateAeroCompatibleBitmap(rc, m_tabCloseHDC); else m_tabCloseBitmap = ::CreateCompatibleBitmap(dc, 20, 20); m_tabCloseOldBitmap = reinterpret_cast(::SelectObject(m_tabCloseHDC, m_tabCloseBitmap)); if (M.isVSThemed() || M.isAero()) { ::FillRect(m_tabCloseHDC, &rc, M.isAero() ? reinterpret_cast(::GetStockObject(BLACK_BRUSH)) : ::GetSysColorBrush(COLOR_3DFACE)); HANDLE hTheme = OpenThemeData(PluginConfig.g_hwndHotkeyHandler, L"BUTTON"); rc.left--; rc.right++; rc.top--; rc.bottom++; DrawThemeParentBackground(PluginConfig.g_hwndHotkeyHandler, m_tabCloseHDC, &rc); DrawThemeBackground(hTheme, m_tabCloseHDC, 1, 1, &rc, &rc); CloseThemeData(hTheme); } else if (CSkin::m_skinEnabled) CSkin::DrawItem(m_tabCloseHDC, &rc, &SkinItems[ID_EXTBKBUTTONSNPRESSED]); else { ::FillRect(m_tabCloseHDC, &rc, ::GetSysColorBrush(COLOR_3DFACE)); ::DrawFrameControl(m_tabCloseHDC, &rc, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_MONO); } ::DrawIconEx(m_tabCloseHDC, 2, 2, PluginConfig.g_buttonBarIcons[ICON_BUTTON_CANCEL], 16, 16, 0, 0, DI_NORMAL); ::SelectObject(m_tabCloseHDC, m_tabCloseOldBitmap); HBITMAP hbmTemp = ResizeBitmap(m_tabCloseBitmap, 16, 16, fFree); ::DeleteObject(m_tabCloseBitmap); m_tabCloseBitmap = hbmTemp; CImageItem::PreMultiply(m_tabCloseBitmap, 1); m_tabCloseOldBitmap = reinterpret_cast(::SelectObject(m_tabCloseHDC, m_tabCloseBitmap)); ::ReleaseDC(PluginConfig.g_hwndHotkeyHandler, dc); } /** * load and setup some images which are used to draw tabs in aero mode * there is one image for tabs (it is flipped vertically for bottom tabs) * and one image for the glowing effect on tabs (also flipped for bottom * tabs). * * support for custom images added 3.0.0.34 * user can place images with a custom_ prefix into the images folder and * they will be loaded instead the default ones. * * the 3rd image acts as background for switch bar buttons * * this is executed when: * ) dwm mode changes * ) aero effect is changed by the user * ) glow colorization is changed by user's request */ void CSkin::setupAeroSkins() { TCHAR tszFilename[MAX_PATH], tszBasePath[MAX_PATH]; M.getAeroState(); UnloadAeroTabs(); BOOL isOpaque; HBITMAP hbm; BITMAP bm; if (!m_fAeroSkinsValid) return; mir_sntprintf(tszBasePath, MAX_PATH, _T("%s"), M.getDataPath()); if (tszBasePath[lstrlen(tszBasePath) - 1] != '\\') _tcscat(tszBasePath, _T("\\")); /* * load unknown avatar.. */ if (0 == PluginConfig.g_hbmUnknown) { mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_unknown.png"), tszBasePath); if (!PathFileExists(tszFilename)) mir_sntprintf(tszFilename, MAX_PATH, _T("%sunknown.png"), tszBasePath); PluginConfig.g_hbmUnknown = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR); if (PluginConfig.g_hbmUnknown == 0) { HDC dc = GetDC(0); PluginConfig.g_hbmUnknown = CreateCompatibleBitmap(dc, 20, 20); ReleaseDC(0, dc); } } mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_tabskin_aero.png"), tszBasePath); if (!PathFileExists(tszFilename)) mir_sntprintf(tszFilename, MAX_PATH, _T("%stabskin_aero.png"), tszBasePath); if (CMimAPI::m_pfnDwmGetColorizationColor && M.isAero()) CMimAPI::m_pfnDwmGetColorizationColor(&m_dwmColor, &isOpaque); else m_dwmColor = PluginConfig.m_fillColor; float fr = (float)((m_dwmColor & 0x00ff0000) >> 16); float fg = (float)((m_dwmColor & 0x0000ff00) >> 8); float fb = (float)((m_dwmColor & 0x000000ff)); BYTE alphafactor = 255 - ((m_dwmColor & 0xff000000) >> 24); /* * a bit tricky, because for low alpha settings (high DWM transparency), the dwm * color is almost dark gray, so we need to intensify the strongest color a bit more than * the others. This will give us a good match for the dwm color that can be used * to render non transparent stuff (i.e. the tool bar). * * TODO: this isn't perfect yet, for some colors, the result is a bit off... */ if (!isOpaque && alphafactor > 150 && !(fr == fg && fg == fb)) { float fmax = max(max(fr,fg), fb); if (fmax == fr) { fr *= (alphafactor / 100 * 2.2); fr = min(fr, 255); fb = min(fb * alphafactor / 100, 255); fg = min(fg * alphafactor / 100, 255); } else if (fmax == fg) { fg *= (alphafactor / 100 * 2.2); fg = min(fg, 255); fr = min(fr * alphafactor / 100, 255); fb = min(fb * alphafactor / 100, 255); } else { fb *= (alphafactor / 100 * 2.2); fb = min(fb, 255); fr = min(fr * alphafactor / 100, 255); fg = min(fg * alphafactor / 100, 255); } } m_dwmColorRGB = RGB((BYTE)fr, (BYTE)fg, (BYTE)fb); FIBITMAP *fib = (FIBITMAP *)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR | IMGL_RETURNDIB); hbm = FIF->FI_CreateHBITMAPFromDIB(fib); CImageItem::Colorize(hbm, GetRValue(m_dwmColorRGB), GetGValue(m_dwmColorRGB), GetBValue(m_dwmColorRGB)); CImageItem::PreMultiply(hbm, 1); GetObject(hbm, sizeof(bm), &bm); m_tabTop = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA, 0, 255, 30, 80, 50, 100); m_tabTop->setAlphaFormat(AC_SRC_ALPHA, 255); m_tabTop->setMetrics(bm.bmWidth, bm.bmHeight); /* * created inverted bitmap for bottom tabs */ FIF->FI_FlipVertical(fib); hbm = FIF->FI_CreateHBITMAPFromDIB(fib); CImageItem::Colorize(hbm, GetRValue(m_dwmColorRGB), GetGValue(m_dwmColorRGB), GetBValue(m_dwmColorRGB)); CImageItem::PreMultiply(hbm, 1); FIF->FI_Unload(fib); GetObject(hbm, sizeof(bm), &bm); m_tabBottom = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA, 0, 255, 30, 80, 50, 100); m_tabBottom->setAlphaFormat(AC_SRC_ALPHA, 255); m_tabBottom->setMetrics(bm.bmWidth, bm.bmHeight); mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_tabskin_aero_glow.png"), tszBasePath); if (!PathFileExists(tszFilename)) mir_sntprintf(tszFilename, MAX_PATH, _T("%stabskin_aero_glow.png"), tszBasePath); fib = (FIBITMAP *)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR | IMGL_RETURNDIB); COLORREF glowColor = M.GetDword(FONTMODULE, "aeroGlow", RGB(40, 40, 255)); hbm = FIF->FI_CreateHBITMAPFromDIB(fib); CImageItem::Colorize(hbm, GetRValue(glowColor), GetGValue(glowColor), GetBValue(glowColor)); CImageItem::PreMultiply(hbm, 1); GetObject(hbm, sizeof(bm), &bm); m_tabGlowTop = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA, 0, 255, 30, 80, 50, 100); m_tabGlowTop->setAlphaFormat(AC_SRC_ALPHA, 255); m_tabGlowTop->setMetrics(bm.bmWidth, bm.bmHeight); FIF->FI_FlipVertical(fib); hbm = FIF->FI_CreateHBITMAPFromDIB(fib); CImageItem::Colorize(hbm, GetRValue(glowColor), GetGValue(glowColor), GetBValue(glowColor)); CImageItem::PreMultiply(hbm, 1); FIF->FI_Unload(fib); GetObject(hbm, sizeof(bm), &bm); m_tabGlowBottom = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA, 0, 255, 30, 80, 50, 100); m_tabGlowBottom->setAlphaFormat(AC_SRC_ALPHA, 255); m_tabGlowBottom->setMetrics(bm.bmWidth, bm.bmHeight); /* * background item for the button switch bar */ mir_sntprintf(tszFilename, MAX_PATH, _T("%scustom_tabskin_aero_button.png"), tszBasePath); if (!PathFileExists(tszFilename)) mir_sntprintf(tszFilename, MAX_PATH, _T("%stabskin_aero_button.png"), tszBasePath); hbm = (HBITMAP)CallService(MS_IMG_LOAD, (WPARAM)tszFilename, IMGL_TCHAR); CImageItem::Colorize(hbm, GetRValue(m_dwmColorRGB), GetGValue(m_dwmColorRGB), GetBValue(m_dwmColorRGB)); CImageItem::PreMultiply(hbm, 1); GetObject(hbm, sizeof(bm), &bm); m_switchBarItem = new CImageItem(4, 4, 4, 4, 0, hbm, IMAGE_FLAG_DIVIDED | IMAGE_PERPIXEL_ALPHA, 0, 255, 2, 12, 10, 20); m_switchBarItem->setAlphaFormat(AC_SRC_ALPHA, 255); m_switchBarItem->setMetrics(bm.bmWidth, bm.bmHeight); } /** * Calculate window frame borders for a skin with the ability to paint the window frame. * Uses system metrics to determine predefined window borders and caption bar size. */ void CSkin::SkinCalcFrameWidth() { int xBorder, yBorder, yCaption; xBorder = GetSystemMetrics(SM_CXSIZEFRAME); yBorder = GetSystemMetrics(SM_CYSIZEFRAME); yCaption = GetSystemMetrics(SM_CYCAPTION); m_realSkinnedFrame_left = m_SkinnedFrame_left - xBorder; m_realSkinnedFrame_right = m_SkinnedFrame_right - xBorder; m_realSkinnedFrame_bottom = m_SkinnedFrame_bottom - yBorder; m_realSkinnedFrame_caption = m_SkinnedFrame_caption - yCaption; } /** * Draws part of the background to the foreground control * * @param hwndClient HWND: target window * @param hwnd HWND: source window (usually the parent, needed for transforming client coordinates * @param pContainer ContainerWindowData *: needed to access the cached DC of the container window * @param rcClient RECT *: client rectangle (target area) * @param hdcTarget HDC: device context of the target window */ void CSkin::SkinDrawBG(HWND hwndClient, HWND hwnd, TContainerData *pContainer, RECT *rcClient, HDC hdcTarget) { RECT rcWindow; POINT pt; LONG width = rcClient->right - rcClient->left; LONG height = rcClient->bottom - rcClient->top; HDC dc; ::GetWindowRect(hwndClient, &rcWindow); pt.x = rcWindow.left + rcClient->left; pt.y = rcWindow.top + rcClient->top; ::ScreenToClient(hwnd, &pt); if (pContainer) dc = pContainer->cachedDC; else dc = ::GetDC(hwnd); pt.y = max(pt.y, 0); ::BitBlt(hdcTarget, rcClient->left, rcClient->top, width, height, dc, pt.x, pt.y, SRCCOPY); if (!pContainer) ::ReleaseDC(hwnd, dc); } /** * Draws part of the background to the foreground control * same as above, but can use any source DC, not just the * container * * @param hwndClient HWND: target window * @param hwnd HWND: source window (usually the parent, needed for transforming client coordinates * @param pContainer ContainerWindowData *: needed to access the cached DC of the container window * @param rcClient RECT *: client rectangle (target area) * @param hdcTarget HDC: device context of the target window */ void CSkin::SkinDrawBGFromDC(HWND hwndClient, HWND hwnd, RECT *rcClient, HDC hdcTarget) { RECT rcWindow; POINT pt; LONG width = rcClient->right - rcClient->left; LONG height = rcClient->bottom - rcClient->top; HDC hdcSrc = ::GetDC(hwnd); ::GetWindowRect(hwndClient, &rcWindow); pt.x = rcWindow.left + rcClient->left; pt.y = rcWindow.top + rcClient->top; ::ScreenToClient(hwnd, &pt); ::StretchBlt(hdcTarget, rcClient->left, rcClient->top, width, height, hdcSrc, pt.x, pt.y, width, height, SRCCOPY | CAPTUREBLT); ::ReleaseDC(hwnd, hdcSrc); } /** * draw an icon "bDimmed" (small amount of transparency applied) */ void CSkin::DrawDimmedIcon(HDC hdc, LONG left, LONG top, LONG dx, LONG dy, HICON hIcon, BYTE alpha) { HDC dcMem = ::CreateCompatibleDC(hdc); HBITMAP hbm = ::CreateCompatibleBitmap(hdc, dx, dy), hbmOld = 0; hbmOld = reinterpret_cast(::SelectObject(dcMem, hbm)); ::DrawIconEx(dcMem, 0, 0, hIcon, dx, dy, 0, 0, DI_NORMAL); m_default_bf.SourceConstantAlpha = alpha; hbm = (HBITMAP)SelectObject(dcMem, hbmOld); CImageItem::PreMultiply(hbm, 1); // for AlphaBlend()... hbmOld = reinterpret_cast(::SelectObject(dcMem, hbm)); GdiAlphaBlend(hdc, left, top, dx, dy, dcMem, 0, 0, dx, dy, m_default_bf); m_default_bf.SourceConstantAlpha = 255; SelectObject(dcMem, hbmOld); DeleteObject(hbm); DeleteDC(dcMem); } UINT CSkin::NcCalcRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC MyWndProc) { NCCALCSIZE_PARAMS *nccp = (NCCALCSIZE_PARAMS *)lParam; BOOL bReturn = FALSE; if (CSkin::m_DisableScrollbars) { SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_VSCROLL); EnableScrollBar(hwnd, SB_VERT, ESB_DISABLE_BOTH); ShowScrollBar(hwnd, SB_VERT, FALSE); } LRESULT orig = mir_callNextSubclass(hwnd, MyWndProc, msg, wParam, lParam); if (0 == mwdat) return orig; if (CSkin::m_skinEnabled) { CSkinItem *item = &SkinItems[skinID]; if (!item->IGNORED) return WVR_REDRAW; } if (mwdat->hTheme && wParam) { RECT rcClient; HDC hdc = GetDC(GetParent(hwnd)); if (GetThemeBackgroundContentRect(mwdat->hTheme, hdc, 1, 1, &nccp->rgrc[0], &rcClient) == S_OK) { if (EqualRect(&rcClient, &nccp->rgrc[0])) InflateRect(&rcClient, -1, -1); CopyRect(&nccp->rgrc[0], &rcClient); bReturn = TRUE; } ReleaseDC(GetParent(hwnd), hdc); if (bReturn) return WVR_REDRAW; else return orig; } if ((mwdat->sendMode & SMODE_MULTIPLE || mwdat->sendMode & SMODE_CONTAINER || mwdat->fEditNotesActive || mwdat->sendMode & SMODE_SENDLATER) && skinID == ID_EXTBKINPUTAREA) { InflateRect(&nccp->rgrc[0], -1, -1); return WVR_REDRAW; } return orig; } /* * process WM_NCPAINT for the rich edit control. Draw a visual style border and avoid classic static edge / client edge * may also draw a colorized border around the control */ UINT CSkin::DrawRichEditFrame(HWND hwnd, const TWindowData *mwdat, UINT skinID, UINT msg, WPARAM wParam, LPARAM lParam, WNDPROC OldWndProc) { // do default processing (otherwise, NO scrollbar as it is painted in NC_PAINT) LRESULT result = mir_callNextSubclass(hwnd, OldWndProc, msg, wParam, lParam); if (0 == mwdat) return result; BOOL isEditNotesReason = ((mwdat->fEditNotesActive) && (skinID == ID_EXTBKINPUTAREA)); BOOL isSendLaterReason = ((mwdat->sendMode & SMODE_SENDLATER) && (skinID == ID_EXTBKINPUTAREA)); BOOL isMultipleReason = ((skinID == ID_EXTBKINPUTAREA) && (mwdat->sendMode & SMODE_MULTIPLE || mwdat->sendMode & SMODE_CONTAINER)); HDC hdc = GetWindowDC(hwnd); RECT rcWindow; POINT pt; LONG left_off, top_off, right_off, bottom_off; LONG dwStyle = GetWindowLongPtr(hwnd, GWL_STYLE); LONG dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); GetWindowRect(hwnd, &rcWindow); pt.x = pt.y = 0; ClientToScreen(hwnd, &pt); left_off = pt.x - rcWindow.left; if (dwStyle & WS_VSCROLL && dwExStyle & WS_EX_RTLREADING) left_off -= PluginConfig.m_ncm.iScrollWidth; top_off = pt.y - rcWindow.top; CSkinItem *item = &SkinItems[skinID]; if (CSkin::m_skinEnabled && !item->IGNORED) { right_off = item->MARGIN_RIGHT; bottom_off = item->MARGIN_BOTTOM; } else { right_off = left_off; bottom_off = top_off; } rcWindow.right -= rcWindow.left; rcWindow.bottom -= rcWindow.top; rcWindow.left = rcWindow.top = 0; ExcludeClipRect(hdc, left_off, top_off, rcWindow.right - right_off, rcWindow.bottom - bottom_off); if (CSkin::m_skinEnabled && !item->IGNORED) { ReleaseDC(hwnd, hdc); return result; } if (isMultipleReason || isEditNotesReason || isSendLaterReason) { HBRUSH br = CreateSolidBrush(isMultipleReason ? RGB(255, 130, 130) : (isEditNotesReason ? RGB(80, 255, 80) : RGB(80, 80, 255))); FillRect(hdc, &rcWindow, br); DeleteObject(br); } else { if (PluginConfig.m_cRichBorders) { HBRUSH br = CreateSolidBrush(PluginConfig.m_cRichBorders); FillRect(hdc, &rcWindow, br); DeleteObject(br); } else DrawThemeBackground(mwdat->hTheme, hdc, 1, 1, &rcWindow, &rcWindow); } ReleaseDC(hwnd, hdc); return result; } /** * convert a html-style color string (without the #) to a 32bit COLORREF value * * @param szSource TCHAR*: the color value as string. format: * html-style without the leading #. e.g. * "f3e355" * * @return COLORREF representation of the string value. */ DWORD __fastcall CSkin::HexStringToLong(const TCHAR *szSource) { TCHAR *stopped; COLORREF clr = _tcstol(szSource, &stopped, 16); if (clr == -1) return clr; return(RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr))); } /** * Render text to the given HDC. This function is aero aware and will use uxtheme DrawThemeTextEx() when needed. * Paramaters are pretty much comparable to GDI DrawText() API * * @return */ int CSkin::RenderText(HDC hdc, HANDLE hTheme, const TCHAR *szText, RECT *rc, DWORD dtFlags, const int iGlowSize, COLORREF clr, bool fForceAero) { if ((PluginConfig.m_bIsVista && !CSkin::m_skinEnabled && hTheme) || fForceAero) { DTTOPTS dto = {0}; dto.dwSize = sizeof(dto); if (iGlowSize && (M.isAero() || fForceAero)) { dto.iGlowSize = iGlowSize; dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE; } else { dto.dwFlags = DTT_TEXTCOLOR|DTT_COMPOSITED;//|DTT_SHADOWTYPE|DTT_SHADOWOFFSET|DTT_SHADOWCOLOR|DTT_BORDERSIZE|DTT_BORDERCOLOR; dto.crText = clr; } dto.iBorderSize = 10; return(CMimAPI::m_pfnDrawThemeTextEx(hTheme, hdc, BP_PUSHBUTTON, PBS_NORMAL, szText, -1, dtFlags, rc, &dto)); } else { ::SetTextColor(hdc, clr); return(::DrawText(hdc, szText, -1, rc, dtFlags)); } } /** * Resize a bitmap using image service. The function does not care about the image aspect ratio. * The caller is responsible to submit proper values for the desired height and width. * * @param hBmpSrc HBITMAP: the source bitmap * @param width LONG: width of the destination bitmap * @param height LONG: height of the new bitmap * @param mustFree bool: indicates that the new bitmap had been *resized and either the source or destination *bitmap should be freed. * * @return HBTIAMP: handle to a bitmap with the desired size. */ HBITMAP CSkin::ResizeBitmap(HBITMAP hBmpSrc, LONG width, LONG height, bool &mustFree) { BITMAP bm; GetObject(hBmpSrc, sizeof(bm), &bm); if (bm.bmHeight != height || bm.bmWidth != width) { ::ResizeBitmap rb; rb.size = sizeof(rb); rb.fit = RESIZEBITMAP_STRETCH; rb.max_height = height; rb.max_width = width; rb.hBmp = hBmpSrc; HBITMAP hbmNew = (HBITMAP)CallService("IMG/ResizeBitmap", (WPARAM)&rb, 0); if (hbmNew != hBmpSrc) mustFree = true; return(hbmNew); } else { mustFree = false; return(hBmpSrc); } } /** * Draw the given skin item to the target rectangle and dc * * @param hdc HDC: device context * @param rc RECT: target rectangle * @param item CSkinItem*: fully initialiized skin item * * @return bool: true if the item has been painted, false if not * (only reason: the ignore flag in the item is set). */ bool __fastcall CSkin::DrawItem(const HDC hdc, const RECT *rc, const CSkinItem *item) { if (!item->IGNORED) { ::DrawAlpha(hdc, const_cast(rc), item->COLOR, item->ALPHA, item->COLOR2, item->COLOR2_TRANSPARENT, item->GRADIENT, item->CORNER, item->BORDERSTYLE, item->imageItem); return true; } return false; } /** * Create a 32bit RGBA bitmap, compatible for rendering with alpha channel. * Required by anything which would render on a transparent aero surface. * the image is a "bottom up" bitmap, as it has a negative * height. This is a requirement for some UxTheme APIs (e.g. * DrawThemeTextEx). * * @param rc RECT &: the rectangle describing the target area. * @param dc The device context for which the bitmap should be created. * * @return HBITMAP: handle to the bitmap created. */ HBITMAP CSkin::CreateAeroCompatibleBitmap(const RECT &rc, HDC dc) { BITMAPINFO dib = {0}; dib.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); dib.bmiHeader.biWidth = rc.right - rc.left; dib.bmiHeader.biHeight = -(rc.bottom - rc.top); dib.bmiHeader.biPlanes = 1; dib.bmiHeader.biBitCount = 32; dib.bmiHeader.biCompression = BI_RGB; return(CreateDIBSection(dc, &dib, DIB_RGB_COLORS, NULL, NULL, 0 )); } /** * Map a given rectangle within the window, specified by hwndClient * to the client area of another window. * * @param hwndClient HWND: Client window * @param hwndParent HWND: The window to which the coordinates should be mapped * @param rc RECT &: Rectangular area within the client area of hwndClient. * *It will receive the transformed coordinates, relative to the client area of hwndParent */ void CSkin::MapClientToParent(HWND hwndClient, HWND hwndParent, RECT &rc) { POINT pt; LONG cx = rc.right - rc.left; LONG cy = rc.bottom - rc.top; pt.x = rc.left; pt.y = rc.top; ::ClientToScreen(hwndClient, &pt); ::ScreenToClient(hwndParent, &pt); rc.top = pt.y; rc.left = pt.x; rc.right = rc.left + cx; rc.bottom = rc.top + cy; } /** * Draw the background for the message window tool bar * * @param dat _MessageWindowData *: structure describing the message session * * @param hdc HDC: handle to the device context in which painting should occur. * @param rcWindow RECT &: The window rectangle of the message dialog window */ void CSkin::RenderToolbarBG(const TWindowData *dat, HDC hdc, const RECT &rcWindow) { if (dat) { if (dat->pContainer->dwFlags & CNT_HIDETOOLBAR) return; bool bAero = M.isAero(); bool fTbColorsValid = PluginConfig.m_tbBackgroundHigh && PluginConfig.m_tbBackgroundLow; BYTE bAlphaOffset = 0; BOOL fMustDrawNonThemed = ((bAero || fTbColorsValid) && !M.GetByte(SRMSGMOD_T, "forceThemedToolbar", 0)); RECT rc, rcToolbar; POINT pt; if (!(dat->pContainer->dwFlags & CNT_BOTTOMTOOLBAR)) { ::GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_CHAT ? IDC_CHAT_LOG : IDC_LOG), &rc); pt.y = rc.bottom + 0; ::ScreenToClient(dat->hwnd, &pt); rcToolbar.top = pt.y; rcToolbar.left = 0; rcToolbar.right = rcWindow.right; if (dat->bType == SESSIONTYPE_IM) { if (dat->dwFlags & MWF_ERRORSTATE) rcToolbar.top += ERRORPANEL_HEIGHT; if (dat->dwFlagsEx & MWF_SHOW_SCROLLINGDISABLED || dat->bNotOnList) { rcToolbar.top += 20; RECT rcAdd; rcAdd.left = 0; rcAdd.right = rcToolbar.right - rcToolbar.left; rcAdd.bottom = rcToolbar.top - 1; rcAdd.top = rcAdd.bottom - 20; ::DrawEdge(hdc, &rcAdd, BDR_RAISEDINNER | BDR_RAISEDOUTER, BF_RECT | BF_SOFT | BF_FLAT); } } ::GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_CHAT ? IDC_CHAT_MESSAGE : IDC_MESSAGE), &rc); pt.y = rc.top - (dat->bIsAutosizingInput ? 1 : 2); ::ScreenToClient(dat->hwnd, &pt); rcToolbar.bottom = pt.y; } else { GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_CHAT ? IDC_CHAT_MESSAGE : IDC_MESSAGE), &rc); pt.y = rc.bottom - (dat->bType == SESSIONTYPE_IM ? 2 : 2); ScreenToClient(dat->hwnd, &pt); rcToolbar.top = pt.y + 1; rcToolbar.left = 0; rcToolbar.right = rcWindow.right; rcToolbar.bottom = rcWindow.bottom; } LONG cx = rcToolbar.right - rcToolbar.left; LONG cy = rcToolbar.bottom - rcToolbar.top; RECT rcCachedToolbar = {0}; rcCachedToolbar.right = cx; rcCachedToolbar.bottom = cy; if (dat->pContainer->cachedToolbarDC == 0) dat->pContainer->cachedToolbarDC = ::CreateCompatibleDC(hdc); if (dat->pContainer->szOldToolbarSize.cx != cx || dat->pContainer->szOldToolbarSize.cy != cy) { if (dat->pContainer->oldhbmToolbarBG) { ::SelectObject(dat->pContainer->cachedToolbarDC, dat->pContainer->oldhbmToolbarBG); ::DeleteObject(dat->pContainer->hbmToolbarBG); } dat->pContainer->hbmToolbarBG = CSkin::CreateAeroCompatibleBitmap(rcCachedToolbar, hdc);// ::CreateCompatibleBitmap(hdc, cx, cy); dat->pContainer->oldhbmToolbarBG = reinterpret_cast(::SelectObject(dat->pContainer->cachedToolbarDC, dat->pContainer->hbmToolbarBG)); } dat->pContainer->szOldToolbarSize.cx = cx; dat->pContainer->szOldToolbarSize.cy = cy; if (!fMustDrawNonThemed && M.isVSThemed()) { DrawThemeBackground(dat->hThemeToolbar, dat->pContainer->cachedToolbarDC, 6, 1, &rcCachedToolbar, &rcCachedToolbar); dat->pContainer->bTBRenderingMode = 1; // tell TSButton how to render the tool bar buttons } else { dat->pContainer->bTBRenderingMode = (M.isVSThemed() ? 1 : 0); m_tmp_tb_high = PluginConfig.m_tbBackgroundHigh ? PluginConfig.m_tbBackgroundHigh : ((bAero && m_pCurrentAeroEffect) ? m_pCurrentAeroEffect->m_clrToolbar : ::GetSysColor(COLOR_3DFACE)); m_tmp_tb_low = PluginConfig.m_tbBackgroundLow ? PluginConfig.m_tbBackgroundLow : ((bAero && m_pCurrentAeroEffect) ? m_pCurrentAeroEffect->m_clrToolbar2 : ::GetSysColor(COLOR_3DFACE)); bAlphaOffset = PluginConfig.m_tbBackgroundHigh ? 40 : 0; ::DrawAlpha(dat->pContainer->cachedToolbarDC, &rcCachedToolbar, m_tmp_tb_high, 55 + bAlphaOffset, m_tmp_tb_low, 0, 9, 0, 0, 0); } ::BitBlt(hdc, rcToolbar.left, rcToolbar.top, cx, cy, dat->pContainer->cachedToolbarDC, 0, 0, SRCCOPY); } } /** * Initiate a buffered paint operation * * @param hdcSrc The source device context (usually obtained by BeginPaint()) * @param rc RECT&: the target rectangle that receives the painting * @param hdcOut HDC& (out) receives the buffered device context handle * * @return */ HANDLE CSkin::InitiateBufferedPaint(const HDC hdcSrc, RECT& rc, HDC& hdcOut) { HANDLE hbp = CMimAPI::m_pfnBeginBufferedPaint(hdcSrc, &rc, BPBF_TOPDOWNDIB, NULL, &hdcOut); return(hbp); } /** * finalize buffered paint cycle and apply (if applicable) the global alpha value * * @param hbp HANDLE: handle of the buffered paint context * @param rc RECT*: target rectangly where alpha value should be applied */ void CSkin::FinalizeBufferedPaint(HANDLE hbp, RECT *rc) { if (m_pCurrentAeroEffect && m_pCurrentAeroEffect->m_finalAlpha > 0) CMimAPI::m_pfnBufferedPaintSetAlpha(hbp, rc, m_pCurrentAeroEffect->m_finalAlpha); CMimAPI::m_pfnEndBufferedPaint(hbp, TRUE); } /** * Apply an effect to a aero glass area * * @param hdc HDC: device context * @param rc RECT*: target rectangle * @param iEffectArea * int: area identifier (specifies which area we are drawing, so that allows to * have different effects on different areas). * Area can be the status bar, info panel, menu * bar etc. * @param hbp HANDLE: handle to a buffered paint identifier. * default is none, needed forsome special * effects. default paramenter is 0 */ void CSkin::ApplyAeroEffect(const HDC hdc, const RECT *rc, int iEffectArea, HANDLE hbp) { if (m_pCurrentAeroEffect == 0 || m_aeroEffect == AERO_EFFECT_NONE) return; if (m_pCurrentAeroEffect->pfnEffectRenderer) m_pCurrentAeroEffect->pfnEffectRenderer(hdc, rc, iEffectArea); } /** aero effect callbacks * */ void CSkin::AeroEffectCallback_Milk(const HDC hdc, const RECT *rc, int iEffectArea) { if (iEffectArea < 0x1000) { int alpha = (iEffectArea == AERO_EFFECT_AREA_INFOPANEL) ? m_pCurrentAeroEffect->m_baseAlpha : 40; if (iEffectArea == AERO_EFFECT_AREA_MENUBAR) alpha = 90; BYTE color2_trans = (iEffectArea == AERO_EFFECT_AREA_MENUBAR) ? 0 : 1; DWORD corner = (iEffectArea == AERO_EFFECT_AREA_INFOPANEL) ? m_pCurrentAeroEffect->m_cornerRadius : 6; DrawAlpha(hdc, const_cast(rc), m_pCurrentAeroEffect->m_baseColor, alpha, m_pCurrentAeroEffect->m_gradientColor, color2_trans, m_pCurrentAeroEffect->m_gradientType, m_pCurrentAeroEffect->m_cornerType, corner, 0); } } void CSkin::AeroEffectCallback_Carbon(const HDC hdc, const RECT *rc, int iEffectArea) { if (iEffectArea < 0x1000) DrawAlpha(hdc, const_cast(rc), m_pCurrentAeroEffect->m_baseColor, m_pCurrentAeroEffect->m_baseAlpha, m_pCurrentAeroEffect->m_gradientColor, 0, m_pCurrentAeroEffect->m_gradientType, m_pCurrentAeroEffect->m_cornerType, m_pCurrentAeroEffect->m_cornerRadius, 0); } void CSkin::AeroEffectCallback_Solid(const HDC hdc, const RECT *rc, int iEffectArea) { if (iEffectArea < 0x1000) { if (iEffectArea == AERO_EFFECT_AREA_SIDEBAR_LEFT) ::DrawAlpha(hdc, const_cast(rc), m_pCurrentAeroEffect->m_baseColor, m_pCurrentAeroEffect->m_baseAlpha, m_pCurrentAeroEffect->m_gradientColor, 0, GRADIENT_TB + 1, 0, 2, 0); else ::DrawAlpha(hdc, const_cast(rc), m_pCurrentAeroEffect->m_baseColor, m_pCurrentAeroEffect->m_baseAlpha, m_pCurrentAeroEffect->m_gradientColor, 0, m_pCurrentAeroEffect->m_gradientType, m_pCurrentAeroEffect->m_cornerType, m_pCurrentAeroEffect->m_cornerRadius, 0); } else { BYTE bGradient = (iEffectArea & AERO_EFFECT_AREA_TAB_BOTTOM ? GRADIENT_BT : GRADIENT_TB) + 1; ::DrawAlpha(hdc, const_cast(rc), m_pCurrentAeroEffect->m_baseColor, 70, m_pCurrentAeroEffect->m_gradientColor, 1, bGradient, m_pCurrentAeroEffect->m_cornerType, m_pCurrentAeroEffect->m_cornerRadius, 0); } } void CSkin::initAeroEffect() { if (m_BrushBack) { ::DeleteObject(m_BrushBack); m_BrushBack = 0; } if (PluginConfig.m_bIsVista && m_aeroEffect > AERO_EFFECT_NONE && m_aeroEffect < AERO_EFFECT_LAST) { m_currentAeroEffect = m_aeroEffects[m_aeroEffect]; m_pCurrentAeroEffect = &m_currentAeroEffect; m_glowSize = m_pCurrentAeroEffect->m_glowSize; if (m_pCurrentAeroEffect->m_clrToolbar == -1) m_pCurrentAeroEffect->m_clrToolbar = PluginConfig.m_ipBackgroundGradientHigh; if (m_pCurrentAeroEffect->m_clrToolbar2 == -1) m_pCurrentAeroEffect->m_clrToolbar2 = PluginConfig.m_ipBackgroundGradient; else if (m_pCurrentAeroEffect->m_clrToolbar2 == 0) m_pCurrentAeroEffect->m_clrToolbar2 = m_dwmColorRGB; if (m_aeroEffect == AERO_EFFECT_CUSTOM || m_aeroEffect == AERO_EFFECT_SOLID) { m_pCurrentAeroEffect->m_baseColor = PluginConfig.m_ipBackgroundGradientHigh; m_pCurrentAeroEffect->m_gradientColor = PluginConfig.m_ipBackgroundGradient; if (m_aeroEffect == AERO_EFFECT_CUSTOM) m_pCurrentAeroEffect->m_clrBack = PluginConfig.m_ipBackgroundGradientHigh; } m_BrushBack = ::CreateSolidBrush(m_pCurrentAeroEffect->m_clrBack); } else { m_pCurrentAeroEffect = 0; m_glowSize = 10; m_BrushBack = ::CreateSolidBrush(0); } for (TContainerData *p = pFirstContainer; p; p = p->pNext) { InvalidateRect(GetDlgItem(p->hwnd, IDC_MSGTABS), NULL, TRUE); InvalidateRect(p->hwnd, NULL, TRUE); if (IsWindow(GetDlgItem(p->hwnd, 5000))) InvalidateRect(GetDlgItem(p->hwnd, 5000), NULL, TRUE); } } void CSkin::setAeroEffect(LRESULT effect) { if (effect == -1) effect = static_cast(M.GetDword(SRMSGMOD_T, "aerostyle", AERO_EFFECT_NONE)); if (effect >= 0 && effect < AERO_EFFECT_LAST) m_aeroEffect = (UINT)effect; else m_aeroEffect = AERO_EFFECT_NONE; initAeroEffect(); db_set_dw(0, SRMSGMOD_T, "aerostyle", m_aeroEffect); } /** * extract the aero skin images from the DLL and store them in * the private data folder. * runs at every startup */ void CSkin::extractSkinsAndLogo(bool fForceOverwrite) const { TCHAR tszBasePath[MAX_PATH]; mir_sntprintf(tszBasePath, MAX_PATH, _T("%s"), M.getDataPath()); if (tszBasePath[lstrlen(tszBasePath) - 1] != '\\') _tcscat(tszBasePath, _T("\\")); CreateDirectoryTreeT(tszBasePath); m_fAeroSkinsValid = true; for (int i=0; i < SIZEOF(my_default_skin); i++) if ( !Utils::extractResource(g_hInst, my_default_skin[i].ulID, _T("SKIN_GLYPH"), tszBasePath, my_default_skin[i].tszName, fForceOverwrite)) m_fAeroSkinsValid = false; } /** * redraw the splitter area between the message input and message log * area only */ void CSkin::UpdateToolbarBG(TWindowData *dat, DWORD dwRdwOptFlags) { RECT rcUpdate, rcTmp; POINT pt; if (dat) { ::GetWindowRect(::GetDlgItem(dat->hwnd, dat->bType == SESSIONTYPE_IM ? IDC_LOG : IDC_CHAT_LOG), &rcTmp); pt.x = rcTmp.left; pt.y = rcTmp.top; ::ScreenToClient(dat->hwnd, &pt); rcUpdate.left = 0; rcUpdate.top = pt.y; ::GetClientRect(dat->hwnd, &rcTmp); rcUpdate.right = rcTmp.right; rcUpdate.bottom = rcTmp.bottom; if (M.isAero() || M.isDwmActive()) dat->fLimitedUpdate = true; // skip unrelevant window updates when we have buffered paint avail ::RedrawWindow(dat->hwnd, &rcUpdate, 0, RDW_INVALIDATE|RDW_ERASE|RDW_UPDATENOW); ::BB_RedrawButtons(dat); dat->fLimitedUpdate = false; } } /** * fill a background area with the default color. This can be either the configured * fill color or default system color. * * @param hdc: device context * @param rc: area to fill. */ void CSkin::FillBack(const HDC hdc, RECT* rc) { if (0 == CSkin::m_BrushFill) { if (PluginConfig.m_fillColor) CSkin::m_BrushFill = ::CreateSolidBrush(PluginConfig.m_fillColor); } if (PluginConfig.m_fillColor) ::FillRect(hdc, rc, CSkin::m_BrushFill); else ::FillRect(hdc, rc, GetSysColorBrush(COLOR_3DFACE)); }