// CommitMonitor - simple checker for new commits in svn repositories
// Copyright (C) 2009 - Stefan Kueng
// 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,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
#include "stdafx.h"
#include "AeroControls.h"
enum ControlType
{
Static,
Button,
Progressbar
};
#ifndef RECTWIDTH
#define RECTWIDTH(rc) ((rc).right-(rc).left)
#endif
#ifndef RECTHEIGHT
#define RECTHEIGHT(rc) ((rc).bottom-(rc).top)
#endif
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
AeroControlBase::AeroControlBase()
{
GdiplusStartupInput gdiplusStartupInput;
m_dwm.Initialize();
m_theme.Initialize();
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
}
AeroControlBase::~AeroControlBase()
{
for (std::map<HWND, UINT_PTR>::const_iterator it = subclassedControls.begin(); it != subclassedControls.end(); ++it)
{
RemoveWindowSubclass(it->first, SubclassProc, it->second);
}
GdiplusShutdown(gdiplusToken);
}
bool AeroControlBase::SubclassControl(HWND hControl)
{
bool bRet = false;
TCHAR szWndClassName[MAX_PATH];
if (GetClassName(hControl, szWndClassName, _countof(szWndClassName)))
{
if (!_tcscmp(szWndClassName, _T("Static")))
{
bRet = !!SetWindowSubclass(hControl, SubclassProc, Static, (DWORD_PTR)this);
subclassedControls[hControl] = Static;
}
if (!_tcscmp(szWndClassName, _T("Button")))
{
bRet = !!SetWindowSubclass(hControl, SubclassProc, Button, (DWORD_PTR)this);
subclassedControls[hControl] = Button;
}
if(!_tcscmp(szWndClassName, _T("msctls_progress32")))
{
bRet = !!SetWindowSubclass(hControl, SubclassProc, Progressbar, (DWORD_PTR)this);
subclassedControls[hControl] = Progressbar;
}
}
return bRet;
}
LRESULT AeroControlBase::SubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uidSubclass, DWORD_PTR dwRefData)
{
AeroControlBase * pThis = (AeroControlBase*)dwRefData;
if (pThis)
{
if (pThis->m_dwm.IsDwmCompositionEnabled())
{
switch (uidSubclass)
{
case Static:
return pThis->StaticWindowProc(hWnd, uMsg, wParam, lParam);
break;
case Button:
return pThis->ButtonWindowProc(hWnd, uMsg, wParam, lParam);
break;
case Progressbar:
return pThis->ProgressbarWindowProc(hWnd, uMsg, wParam, lParam);
break;
}
}
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT AeroControlBase::StaticWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SETTEXT:
case WM_ENABLE:
case WM_STYLECHANGED:
{
LRESULT res = DefSubclassProc(hWnd, uMsg, wParam, lParam);
InvalidateRgn(hWnd, NULL, FALSE);
return res;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if(hdc)
{
HDC hdcPaint = NULL;
RECT rcClient;
GetClientRect(hWnd, &rcClient);
LONG_PTR dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
LONG_PTR dwStyleEx = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
HTHEME hTheme = m_theme.OpenThemeData(NULL, L"ControlPanelStyle");
if(hTheme)
{
HPAINTBUFFER hBufferedPaint = m_theme.BeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB, NULL, &hdcPaint);
if (hdcPaint)
{
PatBlt(hdcPaint, 0, 0, RECTWIDTH(rcClient), RECTHEIGHT(rcClient), BLACKNESS);
m_theme.BufferedPaintSetAlpha(hBufferedPaint, &ps.rcPaint, 0x00);
LONG_PTR dwStaticStyle = dwStyle&0x1F;
if(dwStaticStyle==SS_ICON || dwStaticStyle==SS_BITMAP)
{
bool bIcon = dwStaticStyle==SS_ICON;
HANDLE hBmpIco = (HANDLE)SendMessage(hWnd, STM_GETIMAGE, bIcon ? IMAGE_ICON:IMAGE_BITMAP, NULL);
if(hBmpIco)
{
Bitmap *pBmp = bIcon ? new Bitmap((HICON)hBmpIco) : new Bitmap((HBITMAP)hBmpIco, NULL);
if(pBmp)
{
Graphics* myGraphics = new Graphics(hdcPaint);
if(myGraphics)
{
CachedBitmap *pcbmp = new CachedBitmap(pBmp, myGraphics);
if(pcbmp)
{
myGraphics->DrawCachedBitmap(pcbmp, 0,0);
delete pcbmp;
}
delete myGraphics;
}
delete pBmp;
}
}
}
else if(SS_BLACKRECT==dwStaticStyle || SS_GRAYRECT==dwStaticStyle || SS_WHITERECT==dwStaticStyle)
{
ARGB argb = 0L;
switch (dwStaticStyle)
{
case SS_BLACKRECT:
argb = 0xFF000000;
break;
case SS_GRAYRECT:
argb = 0xFF808080;
break;
case SS_WHITERECT:
argb = 0xFFFFFFFF;
break;
default:
break;
}
Color clr(argb);
FillRect(&rcClient, hdcPaint, clr);
}
else if(SS_BLACKFRAME==dwStaticStyle || SS_GRAYFRAME==dwStaticStyle || SS_WHITEFRAME==dwStaticStyle)
{
ARGB argb = 0L;
switch (dwStaticStyle)
{
case SS_BLACKFRAME:
argb = 0xFF000000;
break;
case SS_GRAYFRAME:
argb = 0xFF808080;
break;
case SS_WHITEFRAME:
argb = 0xFFFFFFFF;
break;
default:
break;
}
Color clr(argb);
DrawRect(&rcClient, hdcPaint, DashStyleSolid, clr, 1.0);
}
else
{
DTTOPTS DttOpts = {sizeof(DTTOPTS)};
DttOpts.dwFlags = DTT_COMPOSITED;
DttOpts.crText = RGB(255, 255, 255);
DttOpts.dwFlags |= DTT_GLOWSIZE;
DttOpts.iGlowSize = 12; // Default value
m_theme.DetermineGlowSize(&DttOpts.iGlowSize);
HFONT hFontOld = (HFONT)SendMessage(hWnd, WM_GETFONT, 0L, NULL);
if(hFontOld)
hFontOld = (HFONT) SelectObject(hdcPaint, hFontOld);
int iLen = GetWindowTextLength(hWnd);
if(iLen)
{
iLen+=5; // 1 for terminating zero, 4 for DT_MODIFYSTRING
LPWSTR szText = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*iLen);
if(szText)
{
iLen = GetWindowTextW(hWnd, szText, iLen);
if(iLen)
{
DWORD dwFlags = DT_WORDBREAK;
switch (dwStaticStyle)
{
case SS_CENTER:
dwFlags |= DT_CENTER;
break;
case SS_RIGHT:
dwFlags |= DT_RIGHT;
break;
case SS_LEFTNOWORDWRAP:
dwFlags &= ~DT_WORDBREAK;
break;
}
if(dwStyle & SS_CENTERIMAGE)
{
dwFlags |= DT_VCENTER;
dwFlags &= ~DT_WORDBREAK;
}
if(dwStyle & SS_ENDELLIPSIS)
dwFlags |= DT_END_ELLIPSIS|DT_MODIFYSTRING;
else if(dwStyle & SS_PATHELLIPSIS)
dwFlags |= DT_PATH_ELLIPSIS|DT_MODIFYSTRING;
else if(dwStyle & SS_WORDELLIPSIS)
dwFlags |= DT_WORD_ELLIPSIS|DT_MODIFYSTRING;
if (dwStyleEx&WS_EX_RIGHT)
dwFlags |= DT_RIGHT;
if(dwStyle & SS_NOPREFIX)
dwFlags |= DT_NOPREFIX;
m_theme.DrawThemeTextEx(hTheme, hdcPaint, 0, 0,
szText, -1, dwFlags, &rcClient, &DttOpts);
if(dwStyle&SS_SUNKEN || dwStyle&WS_BORDER)
DrawRect(&rcClient, hdcPaint, DashStyleSolid, Color(0xFF, 0,0,0), 1.0);
}
LocalFree(szText);
}
}
if (hFontOld)
{
SelectObject(hdcPaint, hFontOld);
hFontOld = NULL;
}
}
m_theme.EndBufferedPaint(hBufferedPaint, TRUE);
}
m_theme.CloseThemeData(hTheme);
}
}
EndPaint(hWnd, &ps);
return 1;
}
break;
case WM_NCDESTROY:
case WM_DESTROY:
RemoveWindowSubclass(hWnd, SubclassProc, Static);
subclassedControls.erase(hWnd);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT AeroControlBase::ButtonWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_SETTEXT:
case WM_ENABLE:
case WM_STYLECHANGED:
{
LRESULT res = DefSubclassProc(hWnd, uMsg, wParam, lParam);
InvalidateRgn(hWnd, NULL, FALSE);
return res;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if(hdc)
{
LONG_PTR dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
LONG_PTR dwButtonStyle = LOWORD(dwStyle);
LONG_PTR dwButtonType = dwButtonStyle&0xF;
RECT rcClient;
GetClientRect(hWnd, &rcClient);
if((dwButtonType&BS_GROUPBOX)==BS_GROUPBOX)
{
///
/// it must be a group box
///
HTHEME hTheme = m_theme.OpenThemeData(hWnd, L"Button");
if(hTheme)
{
HDC hdcPaint = NULL;
BP_PAINTPARAMS params = { sizeof(BP_PAINTPARAMS) };
params.dwFlags = BPPF_ERASE;
RECT rcExclusion = rcClient;
params.prcExclude = &rcExclusion;
///
/// We have to calculate the exclusion rect and therefore
/// calculate the font height. We select the control's font
/// into the DC and fake a drawing operation:
///
HFONT hFontOld = (HFONT)SendMessage(hWnd, WM_GETFONT, 0L, NULL);
if(hFontOld)
hFontOld = (HFONT) SelectObject(hdc, hFontOld);
RECT rcDraw = rcClient;
DWORD dwFlags = DT_SINGLELINE;
///
/// we use uppercase A to determine the height of text, so we
/// can draw the upper line of the groupbox:
///
DrawTextW(hdc, L"A", -1, &rcDraw, dwFlags|DT_CALCRECT);
if (hFontOld)
{
SelectObject(hdc, hFontOld);
hFontOld = NULL;
}
InflateRect(&rcExclusion, -1, -1*RECTHEIGHT(rcDraw));
HPAINTBUFFER hBufferedPaint = m_theme.BeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB,
¶ms, &hdcPaint);
if (hdcPaint)
{
///
/// now we again retrieve the font, but this time we select it into
/// the buffered DC:
///
hFontOld = (HFONT)SendMessage(hWnd, WM_GETFONT, 0L, NULL);
if(hFontOld)
hFontOld = (HFONT) SelectObject(hdcPaint, hFontOld);
PatBlt(hdcPaint, 0, 0, RECTWIDTH(rcClient), RECTHEIGHT(rcClient), BLACKNESS);
m_theme.BufferedPaintSetAlpha(hBufferedPaint, &ps.rcPaint, 0x00);
int iState = GBS_NORMAL;
int iPartId = BP_GROUPBOX;
iState = GetStateFromBtnState(dwStyle, FALSE, FALSE, 0L, iPartId, FALSE);
DTTOPTS DttOpts = {sizeof(DTTOPTS)};
DttOpts.dwFlags = DTT_COMPOSITED;
DttOpts.crText = RGB(255, 255, 255);
DttOpts.dwFlags |= DTT_GLOWSIZE;
DttOpts.iGlowSize = 12; // Default value
m_theme.DetermineGlowSize(&DttOpts.iGlowSize);
Pen* myPen;
Graphics* myGraphics;
COLORREF cr = RGB(0x00, 0x00, 0x00);
GetEditBorderColor(hWnd, &cr);
///
/// add the alpha value:
///
cr |= 0xff000000;
myPen = new Pen(Color(cr), 1);
if(myPen)
{
myGraphics = new Graphics(hdcPaint);
if(myGraphics)
{
int iY = RECTHEIGHT(rcDraw)/2;
Rect rr = Rect(rcClient.left, rcClient.top+iY,
RECTWIDTH(rcClient), RECTHEIGHT(rcClient)-iY-1);
GraphicsPath path;
GetRoundRectPath(&path, rr, 10);
myGraphics->DrawPath(myPen, &path);
//myGraphics->DrawRectangle(myPen, rcClient.left, rcClient.top + iY,
// RECTWIDTH(rcClient)-1, RECTHEIGHT(rcClient) - iY-1);
delete myGraphics;
}
delete myPen;
}
int iLen = GetWindowTextLength(hWnd);
if(iLen)
{
iLen+=5; // 1 for terminating zero, 4 for DT_MODIFYSTRING
LPWSTR szText = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*iLen);
if(szText)
{
iLen = GetWindowTextW(hWnd, szText, iLen);
if(iLen)
{
int iX = RECTWIDTH(rcDraw);
rcDraw = rcClient;
rcDraw.left += iX;
DrawTextW(hdcPaint, szText, -1, &rcDraw, dwFlags|DT_CALCRECT);
PatBlt(hdcPaint, rcDraw.left, rcDraw.top , RECTWIDTH(rcDraw) + 3, RECTHEIGHT(rcDraw), BLACKNESS);
rcDraw.left++;
rcDraw.right++;
m_theme.DrawThemeTextEx(hTheme, hdcPaint, iPartId, iState, szText, -1,
dwFlags, &rcDraw, &DttOpts);
}
LocalFree(szText);
}
}
if (hFontOld)
{
SelectObject(hdcPaint, hFontOld);
hFontOld = NULL;
}
m_theme.EndBufferedPaint(hBufferedPaint, TRUE);
}
m_theme.CloseThemeData(hTheme);
}
}
else if(dwButtonType==BS_CHECKBOX || dwButtonType==BS_AUTOCHECKBOX ||
dwButtonType==BS_3STATE || dwButtonType==BS_AUTO3STATE || dwButtonType==BS_RADIOBUTTON || dwButtonType==BS_AUTORADIOBUTTON)
{
HTHEME hTheme = m_theme.OpenThemeData(hWnd, L"Button");
if(hTheme)
{
HDC hdcPaint = NULL;
BP_PAINTPARAMS params = { sizeof(BP_PAINTPARAMS) };
params.dwFlags = BPPF_ERASE;
HPAINTBUFFER hBufferedPaint = m_theme.BeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB, ¶ms, &hdcPaint);
if (hdcPaint)
{
PatBlt(hdcPaint, 0, 0, RECTWIDTH(rcClient), RECTHEIGHT(rcClient), BLACKNESS);
m_theme.BufferedPaintSetAlpha(hBufferedPaint, &ps.rcPaint, 0x00);
int iState = CBS_UNCHECKEDNORMAL;
LRESULT dwCheckState = SendMessage(hWnd, BM_GETCHECK, 0, NULL);
POINT pt;
RECT rc;
GetWindowRect(hWnd, &rc);
GetCursorPos(&pt);
BOOL bHot = PtInRect(&rc, pt);
BOOL bFocus = GetFocus()==hWnd;
int iPartId = BP_CHECKBOX;
if(dwButtonType==BS_RADIOBUTTON || dwButtonType==BS_AUTORADIOBUTTON)
iPartId = BP_RADIOBUTTON;
iState = GetStateFromBtnState(dwStyle, bHot, bFocus, dwCheckState, iPartId, FALSE);
HBITMAP hbmp = NULL;
m_theme.GetThemeBitmap(hTheme, iPartId, iState, 0,
GBF_DIRECT, &hbmp);
SIZE st;
GetBitmapDimensionEx(hbmp, &st);
BITMAP bm;
GetObject(hbmp, sizeof(BITMAP), &bm);
UINT uiHalfWidth = (RECTWIDTH(rcClient) - bm.bmWidth)/2;
///
/// we have to use the whole client area, otherwise we get only partially
/// drawn areas:
///
RECT rcPaint = rcClient;
if(dwButtonStyle & BS_LEFTTEXT)
{
rcPaint.left += uiHalfWidth;
rcPaint.right += uiHalfWidth;
}
else
{
rcPaint.left -= uiHalfWidth;
rcPaint.right -= uiHalfWidth;
}
///
/// we assume that bm.bmWidth is both the horizontal and the vertical
/// dimension of the control bitmap and that it is square. bm.bmHeight
/// seems to be the height of a striped bitmap because it is an absurdly
/// high dimension value
///
if((dwButtonStyle&BS_VCENTER)==BS_VCENTER) /// BS_VCENTER is BS_TOP|BS_BOTTOM
{
/// nothing to do, verticallly centered
}
else if(dwButtonStyle&BS_TOP)
{
rcPaint.bottom = rcPaint.top + bm.bmWidth;
}
else if(dwButtonStyle&BS_BOTTOM)
{
rcPaint.top = rcPaint.bottom - bm.bmWidth;
}
m_theme.DrawThemeBackground(hTheme, hdcPaint, iPartId, iState, &rcPaint, NULL);
rcPaint = rcClient;
m_theme.GetThemeBackgroundContentRect(hTheme, hdcPaint, iPartId, iState, &rcPaint, &rc);
if(dwButtonStyle & BS_LEFTTEXT)
rc.right -= bm.bmWidth+(bm.bmWidth>>1);
else
rc.left += bm.bmWidth+(bm.bmWidth>>1);
DTTOPTS DttOpts = {sizeof(DTTOPTS)};
DttOpts.dwFlags = DTT_COMPOSITED;
DttOpts.crText = RGB(255, 255, 255);
DttOpts.dwFlags |= DTT_GLOWSIZE;
DttOpts.iGlowSize = 12; // Default value
m_theme.DetermineGlowSize(&DttOpts.iGlowSize);
HFONT hFontOld = (HFONT)SendMessage(hWnd, WM_GETFONT, 0L, NULL);
if(hFontOld)
hFontOld = (HFONT) SelectObject(hdcPaint, hFontOld);
int iLen = GetWindowTextLength(hWnd);
if(iLen)
{
iLen+=5; // 1 for terminating zero, 4 for DT_MODIFYSTRING
LPWSTR szText = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*iLen);
if(szText)
{
iLen = GetWindowTextW(hWnd, szText, iLen);
if(iLen)
{
DWORD dwFlags = DT_SINGLELINE /*|DT_VCENTER*/;
if(dwButtonStyle&BS_MULTILINE)
{
dwFlags|=DT_WORDBREAK;
dwFlags&= ~(DT_SINGLELINE |DT_VCENTER);
}
if((dwButtonStyle&BS_CENTER)==BS_CENTER) /// BS_CENTER is BS_LEFT|BS_RIGHT
dwFlags|=DT_CENTER;
else if(dwButtonStyle&BS_LEFT)
dwFlags|=DT_LEFT;
else if(dwButtonStyle&BS_RIGHT)
dwFlags|=DT_RIGHT;
if((dwButtonStyle&BS_VCENTER)==BS_VCENTER) /// BS_VCENTER is BS_TOP|BS_BOTTOM
dwFlags|=DT_VCENTER;
else if(dwButtonStyle&BS_TOP)
dwFlags|=DT_TOP;
else if(dwButtonStyle&BS_BOTTOM)
dwFlags|=DT_BOTTOM;
else
dwFlags|=DT_VCENTER;
m_theme.DrawThemeTextEx(hTheme, hdcPaint, iPartId,
iState, szText, -1, dwFlags, &rc, &DttOpts);
///
/// if our control has the focus, we also have to draw the focus rectangle:
///
if(bFocus)
{
///
/// now calculate the text size:
///
RECT rcDraw = rc;
///
/// we use GDI's good old DrawText, because it returns much more
/// accurate data than DrawThemeTextEx, which takes the glow
/// into account which we don't want:
///
DrawTextW(hdcPaint, szText, -1, &rcDraw, dwFlags|DT_CALCRECT);
if(dwFlags&DT_SINGLELINE)
{
dwFlags &= ~DT_VCENTER;
RECT rcDrawTop;
DrawTextW(hdcPaint, szText, -1, &rcDrawTop, dwFlags|DT_CALCRECT);
rcDraw.top = rcDraw.bottom - RECTHEIGHT(rcDrawTop);
}
if(dwFlags & DT_RIGHT)
{
int iWidth = RECTWIDTH(rcDraw);
rcDraw.right = rc.right;
rcDraw.left = rcDraw.right - iWidth;
}
RECT rcFocus;
IntersectRect(&rcFocus, &rc, &rcDraw);
DrawFocusRect(&rcFocus, hdcPaint);
}
}
LocalFree(szText);
}
}
if (hFontOld)
{
SelectObject(hdcPaint, hFontOld);
hFontOld = NULL;
}
m_theme.EndBufferedPaint(hBufferedPaint, TRUE);
}
m_theme.CloseThemeData(hTheme);
}
}
else if(BS_PUSHBUTTON==dwButtonType || BS_DEFPUSHBUTTON==dwButtonType)
{
///
/// it is a push button
///
HTHEME hTheme = m_theme.OpenThemeData(hWnd, L"Button");
if(hTheme)
{
HDC hdcPaint = NULL;
BP_PAINTPARAMS params = { sizeof(BP_PAINTPARAMS) };
params.dwFlags = BPPF_ERASE;
HPAINTBUFFER hBufferedPaint = m_theme.BeginBufferedPaint(hdc, &rcClient, BPBF_TOPDOWNDIB, ¶ms, &hdcPaint);
if (hdcPaint)
{
PatBlt(hdcPaint, 0, 0, RECTWIDTH(rcClient), RECTHEIGHT(rcClient), BLACKNESS);
m_theme.BufferedPaintSetAlpha(hBufferedPaint, &ps.rcPaint, 0x00);
int iState = CBS_UNCHECKEDNORMAL;
LRESULT dwCheckState = SendMessage(hWnd, BM_GETCHECK, 0, NULL);
POINT pt;
RECT rc;
GetWindowRect(hWnd, &rc);
GetCursorPos(&pt);
BOOL bHot = PtInRect(&rc, pt);
BOOL bFocus = GetFocus()==hWnd;
int iPartId = BP_PUSHBUTTON;
if(dwButtonStyle==BS_RADIOBUTTON || dwButtonStyle==BS_AUTORADIOBUTTON)
iPartId = BP_RADIOBUTTON;
iState = GetStateFromBtnState(dwStyle, bHot, bFocus, dwCheckState, iPartId, GetCapture()==hWnd);
///
/// we have to use the whole client area, otherwise we get only partially
/// drawn areas:
///
RECT rcPaint = rcClient;
m_theme.DrawThemeBackground(hTheme, hdcPaint, iPartId, iState, &rcPaint, NULL);
m_theme.GetThemeBackgroundContentRect(hTheme, hdcPaint, iPartId, iState, &rcPaint, &rc);
DTTOPTS DttOpts = {sizeof(DTTOPTS)};
DttOpts.dwFlags = DTT_COMPOSITED;
DttOpts.crText = RGB(255, 255, 255);
DttOpts.dwFlags |= DTT_GLOWSIZE;
DttOpts.iGlowSize = 12; // Default value
m_theme.DetermineGlowSize(&DttOpts.iGlowSize);
HFONT hFontOld = (HFONT)SendMessage(hWnd, WM_GETFONT, 0L, NULL);
if(hFontOld)
hFontOld = (HFONT) SelectObject(hdcPaint, hFontOld);
int iLen = GetWindowTextLength(hWnd);
if(iLen)
{
iLen+=5; // 1 for terminating zero, 4 for DT_MODIFYSTRING
LPWSTR szText = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*iLen);
if(szText)
{
iLen = GetWindowTextW(hWnd, szText, iLen);
if(iLen)
{
DWORD dwFlags = DT_SINGLELINE | DT_CENTER | DT_VCENTER;
m_theme.DrawThemeTextEx(hTheme, hdcPaint,
iPartId, iState, szText, -1, dwFlags, &rc, &DttOpts);
///
/// if our control has the focus, we also have to draw the focus rectangle:
///
if(bFocus)
{
RECT rcDraw = rcClient;
InflateRect(&rcDraw, -3, -3);
DrawFocusRect(&rcDraw, hdcPaint);
}
}
LocalFree(szText);
}
}
if (hFontOld)
{
SelectObject(hdcPaint, hFontOld);
hFontOld = NULL;
}
m_theme.EndBufferedPaint(hBufferedPaint, TRUE);
}
m_theme.CloseThemeData(hTheme);
}
}
else
//PaintControl(hWnd, hdc, &ps.rcPaint, (m_dwFlags & WD_DRAW_BORDER)!=0);
PaintControl(hWnd, hdc, &ps.rcPaint, false);
}
EndPaint(hWnd, &ps);
return 0;
}
break;
case WM_DESTROY:
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, SubclassProc, Button);
subclassedControls.erase(hWnd);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
LRESULT AeroControlBase::ProgressbarWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_ENABLE:
case WM_STYLECHANGED:
{
LRESULT res = DefSubclassProc(hWnd, uMsg, wParam, lParam);
InvalidateRgn(hWnd, NULL, FALSE);
return res;
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetWindowRect(hWnd, &rc);
MapWindowPoints(NULL, hWnd, (LPPOINT) &rc, 2);
if(hdc)
{
PaintControl(hWnd, hdc, &rc, false);
BP_PAINTPARAMS params = { sizeof(BP_PAINTPARAMS) };
params.dwFlags = 0L;
HDC hdcPaint = NULL;
params.dwFlags = 0L;
HPAINTBUFFER hBufferedPaint = m_theme.BeginBufferedPaint(hdc, &rc, BPBF_TOPDOWNDIB, ¶ms, &hdcPaint);
if (hdcPaint)
{
COLORREF cr = RGB(0x00, 0x00, 0x00);
SetPixel(hdcPaint, 0, 0, cr);
SetPixel(hdcPaint, 0, RECTHEIGHT(rc) - 1, cr);
SetPixel(hdcPaint, RECTWIDTH(rc) - 1, 0, cr);
SetPixel(hdcPaint, RECTWIDTH(rc) - 1, RECTHEIGHT(rc) - 1, cr);
m_theme.EndBufferedPaint(hBufferedPaint, TRUE);
}
}
EndPaint(hWnd, &ps);
return 1;
}
break;
case WM_NCDESTROY:
case WM_DESTROY:
RemoveWindowSubclass(hWnd, SubclassProc, Static);
subclassedControls.erase(hWnd);
break;
}
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
void AeroControlBase::FillRect(LPRECT prc, HDC hdcPaint, Color clr)
{
Graphics* myGraphics;
SolidBrush *pBrush = new SolidBrush(clr);
if(pBrush)
{
myGraphics = new Graphics(hdcPaint);
if(myGraphics)
{
myGraphics->FillRectangle(pBrush, prc->left, prc->top,
prc->right - 1 - prc->left, prc->bottom - 1 - prc->top);
delete myGraphics;
}
delete pBrush;
}
}
int AeroControlBase::GetStateFromBtnState(LONG_PTR dwStyle, BOOL bHot, BOOL bFocus, LRESULT dwCheckState, int iPartId, BOOL bHasMouseCapture)
{
int iState = 0;
switch (iPartId)
{
case BP_PUSHBUTTON:
iState = PBS_NORMAL;
if (dwStyle&WS_DISABLED)
iState = PBS_DISABLED;
else
{
if(dwStyle&BS_DEFPUSHBUTTON)
iState = PBS_DEFAULTED;
if(bHasMouseCapture && bHot)
iState = PBS_PRESSED;
else if (bHasMouseCapture || bHot)
iState = PBS_HOT;
}
break;
case BP_GROUPBOX:
iState = (dwStyle & WS_DISABLED)?GBS_DISABLED:GBS_NORMAL;
break;
case BP_RADIOBUTTON:
iState = RBS_UNCHECKEDNORMAL;
switch(dwCheckState)
{
case BST_CHECKED:
if (dwStyle&WS_DISABLED)
iState = RBS_CHECKEDDISABLED;
else if(bFocus)
iState = RBS_CHECKEDPRESSED;
else if(bHot)
iState = RBS_CHECKEDHOT;
else
iState = RBS_CHECKEDNORMAL;
break;
case BST_UNCHECKED:
if (dwStyle&WS_DISABLED)
iState = RBS_UNCHECKEDDISABLED;
else if(bFocus)
iState = RBS_UNCHECKEDPRESSED;
else if(bHot)
iState = RBS_UNCHECKEDHOT;
else
iState = RBS_UNCHECKEDNORMAL;
break;
}
break;
case BP_CHECKBOX:
switch(dwCheckState)
{
case BST_CHECKED:
if (dwStyle&WS_DISABLED)
iState = CBS_CHECKEDDISABLED;
else if(bFocus)
iState = CBS_CHECKEDPRESSED;
else if(bHot)
iState = CBS_CHECKEDHOT;
else
iState = CBS_CHECKEDNORMAL;
break;
case BST_INDETERMINATE:
if (dwStyle&WS_DISABLED)
iState = CBS_MIXEDDISABLED;
else if(bFocus)
iState = CBS_MIXEDPRESSED;
else if(bHot)
iState = CBS_MIXEDHOT;
else
iState = CBS_MIXEDNORMAL;
break;
case BST_UNCHECKED:
if (dwStyle&WS_DISABLED)
iState = CBS_UNCHECKEDDISABLED;
else if(bFocus)
iState = CBS_UNCHECKEDPRESSED;
else if(bHot)
iState = CBS_UNCHECKEDHOT;
else
iState = CBS_UNCHECKEDNORMAL;
break;
}
break;
default:
break;
}
return iState;
}
void AeroControlBase::DrawRect(LPRECT prc, HDC hdcPaint, DashStyle dashStyle, Color clr, REAL width)
{
Pen* myPen;
Graphics* myGraphics;
myPen = new Pen(clr, width);
if(myPen)
{
myPen->SetDashStyle(dashStyle);
myGraphics = new Graphics(hdcPaint);
if(myGraphics)
{
myGraphics->DrawRectangle(myPen, prc->left, prc->top,
prc->right - 1 - prc->left, prc->bottom - 1 - prc->top);
delete myGraphics;
}
delete myPen;
}
}
void AeroControlBase::DrawFocusRect(LPRECT prcFocus, HDC hdcPaint)
{
DrawRect(prcFocus, hdcPaint, DashStyleDot, Color(0xFF, 0,0,0), 1.0);
};
void AeroControlBase::PaintControl(HWND hWnd, HDC hdc, RECT* prc, bool bDrawBorder)
{
HDC hdcPaint = NULL;
if(bDrawBorder)
InflateRect(prc, 1, 1);
HPAINTBUFFER hBufferedPaint = m_theme.BeginBufferedPaint(hdc, prc, BPBF_TOPDOWNDIB, NULL, &hdcPaint);
if (hdcPaint)
{
RECT rc;
GetWindowRect(hWnd, &rc);
PatBlt(hdcPaint, 0, 0, RECTWIDTH(rc), RECTHEIGHT(rc), BLACKNESS);
m_theme.BufferedPaintSetAlpha(hBufferedPaint, &rc, 0x00);
///
/// first blit white so list ctrls don't look ugly:
///
PatBlt(hdcPaint, 0, 0, RECTWIDTH(rc), RECTHEIGHT(rc), WHITENESS);
if(bDrawBorder)
InflateRect(prc, -1, -1);
// Tell the control to paint itself in our memory buffer
SendMessage(hWnd, WM_PRINTCLIENT, (WPARAM) hdcPaint, PRF_CLIENT|PRF_ERASEBKGND |PRF_NONCLIENT|PRF_CHECKVISIBLE);
if(bDrawBorder)
{
InflateRect(prc, 1, 1);
FrameRect(hdcPaint, prc, (HBRUSH)GetStockObject(BLACK_BRUSH));
}
// Make every pixel opaque
m_theme.BufferedPaintMakeOpaque_(hBufferedPaint, prc);
m_theme.EndBufferedPaint(hBufferedPaint, TRUE);
}
}
BOOL AeroControlBase::GetEditBorderColor(HWND hWnd, COLORREF *pClr)
{
HTHEME hTheme = m_theme.OpenThemeData(hWnd, L"Edit");
if(hTheme)
{
m_theme.GetThemeColor(hTheme, EP_BACKGROUNDWITHBORDER, EBWBS_NORMAL, TMT_BORDERCOLOR, pClr);
m_theme.CloseThemeData(hTheme);
return TRUE;
}
return FALSE;
}
void AeroControlBase::DrawEditBorder(HWND hWnd)
{
LONG_PTR dwStyleEx = GetWindowLongPtr(hWnd, GWL_EXSTYLE);
if(!(dwStyleEx&WS_EX_CLIENTEDGE))
return;
COLORREF cr = RGB(0x00, 0x00, 0x00);
GetEditBorderColor(hWnd, &cr);
Color clr;
clr.SetFromCOLORREF(cr);
DrawSolidWndRectOnParent(hWnd, clr );
}
void AeroControlBase::DrawSolidWndRectOnParent(HWND hWnd, Color clr)
{
RECT rcWnd;
GetWindowRect(hWnd, &rcWnd);
HWND hParent = GetParent(hWnd);
if(hParent)
{
ScreenToClient(hParent, &rcWnd);
HDC hdc = GetDC(hParent);
if(hdc)
{
DrawRect(&rcWnd, hdc, DashStyleSolid, clr, 1.0);
ReleaseDC(hWnd, hdc);
}
}
}
void AeroControlBase::ScreenToClient(HWND hWnd, LPRECT lprc)
{
POINT pt;
pt.x = lprc->left;
pt.y = lprc->top;
::ScreenToClient(hWnd, &pt);
lprc->left = pt.x;
lprc->top = pt.y;
pt.x = lprc->right;
pt.y = lprc->bottom;
::ScreenToClient(hWnd, &pt);
lprc->right = pt.x;
lprc->bottom = pt.y;
}
void AeroControlBase::GetRoundRectPath(GraphicsPath *pPath, Rect r, int dia)
{
// diameter can't exceed width or height
if(dia > r.Width) dia = r.Width;
if(dia > r.Height) dia = r.Height;
// define a corner
Rect Corner(r.X, r.Y, dia, dia);
// begin path
pPath->Reset();
pPath->StartFigure();
// top left
pPath->AddArc(Corner, 180, 90);
// top right
Corner.X += (r.Width - dia - 1);
pPath->AddArc(Corner, 270, 90);
// bottom right
Corner.Y += (r.Height - dia - 1);
pPath->AddArc(Corner, 0, 90);
// bottom left
Corner.X -= (r.Width - dia - 1);
pPath->AddArc(Corner, 90, 90);
// end path
pPath->CloseFigure();
}