249 lines
6.5 KiB
C++
249 lines
6.5 KiB
C++
/*
|
|
* This is a part of the BugTrap package.
|
|
* Copyright (c) 2005-2009 IntelleSoft.
|
|
* All rights reserved.
|
|
*
|
|
* Description: Animated progress bar control.
|
|
* Author: Maksim Pyatkovskiy.
|
|
*
|
|
* This source code is only intended as a supplement to the
|
|
* BugTrap package reference and related electronic documentation
|
|
* provided with the product. See these sources for detailed
|
|
* information regarding the BugTrap package.
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "AnimProgressBar.h"
|
|
#include "ThemeXP.h"
|
|
|
|
#define USE_MEM_DC
|
|
|
|
#define TIMER_ID 101
|
|
#define DEFAULT_TIMEOUT 5
|
|
#define DEFAULT_NUM_CHUNKS 5
|
|
|
|
CAnimProgressBar::CAnimProgressBar(void)
|
|
{
|
|
m_bActive = FALSE;
|
|
m_dwTimeout = DEFAULT_TIMEOUT;
|
|
m_dwNumChunks = DEFAULT_NUM_CHUNKS;
|
|
m_dwPosition = 0;
|
|
m_hwnd = NULL;
|
|
m_pfnAnimProgressBarWndProc = NULL;
|
|
}
|
|
|
|
/**
|
|
* @param hwnd - progress bar window handle.
|
|
*/
|
|
void CAnimProgressBar::Attach(HWND hwnd)
|
|
{
|
|
_ASSERTE(hwnd != NULL);
|
|
_ASSERTE(m_hwnd == NULL);
|
|
m_hwnd = hwnd;
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
|
m_pfnAnimProgressBarWndProc = SubclassWindow(hwnd, AnimProgressBarWndProc);
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
}
|
|
|
|
void CAnimProgressBar::Detach(void)
|
|
{
|
|
if (m_pfnAnimProgressBarWndProc)
|
|
{
|
|
Stop();
|
|
SubclassWindow(m_hwnd, m_pfnAnimProgressBarWndProc);
|
|
SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL);
|
|
InvalidateRect(m_hwnd, NULL, TRUE);
|
|
m_pfnAnimProgressBarWndProc = NULL;
|
|
m_hwnd = NULL;
|
|
}
|
|
}
|
|
|
|
void CAnimProgressBar::Play()
|
|
{
|
|
if (m_bActive)
|
|
return;
|
|
m_bActive = TRUE;
|
|
SetTimer(m_hwnd, TIMER_ID, m_dwTimeout, NULL);
|
|
}
|
|
|
|
void CAnimProgressBar::Stop()
|
|
{
|
|
if (! m_bActive)
|
|
return;
|
|
m_bActive = FALSE;
|
|
KillTimer(m_hwnd, TIMER_ID);
|
|
}
|
|
|
|
/**
|
|
* @param dwTimeout - new update timeout.
|
|
*/
|
|
void CAnimProgressBar::SetTimeout(DWORD dwTimeout)
|
|
{
|
|
m_dwTimeout = dwTimeout;
|
|
if (m_bActive)
|
|
SetTimer(m_hwnd, TIMER_ID, dwTimeout, NULL);
|
|
}
|
|
|
|
/**
|
|
* @param hdc - drawing context.
|
|
* @param prcPaint - the rectangle where the painting is requested.
|
|
*/
|
|
void CAnimProgressBar::DrawAnimProgressBar(HDC hdc, const RECT* prcPaint) const
|
|
{
|
|
if (prcPaint == NULL)
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(m_hwnd, &rcClient);
|
|
prcPaint = &rcClient;
|
|
}
|
|
if (IsRectEmpty(prcPaint))
|
|
return;
|
|
|
|
#ifdef USE_MEM_DC
|
|
int nClientWidth = prcPaint->right - prcPaint->left;
|
|
int nClientHeight = prcPaint->bottom - prcPaint->top;
|
|
HBITMAP hbmpMem;
|
|
hbmpMem = CreateCompatibleBitmap(hdc, nClientWidth, nClientHeight);
|
|
if (hbmpMem == NULL)
|
|
return;
|
|
HDC hdcMem;
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
if (hdcMem == NULL)
|
|
{
|
|
DeleteBitmap(hbmpMem);
|
|
return;
|
|
}
|
|
SetViewportOrgEx(hdcMem, -prcPaint->left, -prcPaint->top, NULL);
|
|
HBITMAP hbmpSafe = SelectBitmap(hdcMem, hbmpMem);
|
|
#else
|
|
// CS_PARENTDC sets the clipping rectangle of the child window to that of the parent window
|
|
// so that the child can draw on the parent. Progress bar inherits this style from sub-classed
|
|
// static control. This causes problems with unclipped output.
|
|
HRGN hrgn = CreateRectRgnIndirect(prcPaint);
|
|
SelectClipRgn(hdc, hrgn);
|
|
DeleteRgn(hrgn);
|
|
HDC hdcMem = hdc;
|
|
#endif
|
|
|
|
CThemeXP themeXP;
|
|
BOOL bAppThemed = themeXP.IsAppThemed();
|
|
if (bAppThemed)
|
|
{
|
|
if (! themeXP.OpenTheme(m_hwnd, L"PROGRESS"))
|
|
bAppThemed = FALSE;
|
|
}
|
|
|
|
RECT rcClient;
|
|
GetClientRect(m_hwnd, &rcClient);
|
|
RECT rcClip;
|
|
GetClipBox(hdc, &rcClip);
|
|
|
|
if (bAppThemed)
|
|
{
|
|
themeXP.DrawThemeBackground(hdcMem, PP_BAR, 0, &rcClient, &rcClip);
|
|
RECT rcContent;
|
|
themeXP.GetThemeBackgroundContentRect(hdcMem, PP_BAR, 0, &rcClient, &rcContent);
|
|
SIZE szChunk;
|
|
themeXP.GetThemePartSize(hdcMem, PP_CHUNK, 0, &rcContent, TS_TRUE, &szChunk);
|
|
if (szChunk.cx <= 1)
|
|
szChunk.cx = szChunk.cy * 3 / 4;
|
|
DWORD dwChunksWidth = m_dwNumChunks * szChunk.cx;
|
|
DWORD dwPosition = m_dwPosition % (rcContent.right - rcContent.left + dwChunksWidth);
|
|
int nPosition = (int)dwPosition - (int)dwChunksWidth;
|
|
RECT rcChunk;
|
|
rcChunk.left = rcContent.left + nPosition;
|
|
rcChunk.top = rcContent.top;
|
|
rcChunk.bottom = rcContent.bottom;
|
|
for (DWORD dwChunkNum = 0; dwChunkNum < m_dwNumChunks; ++dwChunkNum)
|
|
{
|
|
rcChunk.right = rcChunk.left + szChunk.cx;
|
|
if (rcClip.left <= rcChunk.right && rcChunk.left < rcClip.right)
|
|
themeXP.DrawThemeBackground(hdcMem, PP_CHUNK, 0, &rcChunk, &rcClip);
|
|
rcChunk.left = rcChunk.right;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
HBRUSH brushBtnFace = GetSysColorBrush(COLOR_BTNFACE);
|
|
FillRect(hdcMem, &rcClip, brushBtnFace);
|
|
HBRUSH brushHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
|
|
int nCXEdge = GetSystemMetrics(SM_CXEDGE);
|
|
int nCYEdge = GetSystemMetrics(SM_CYEDGE);
|
|
SIZE szChunk;
|
|
szChunk.cy = rcClient.bottom - rcClient.top;
|
|
szChunk.cx = szChunk.cy * 3 / 4;
|
|
DWORD dwChunksWidth = m_dwNumChunks * szChunk.cx;
|
|
DWORD dwPosition = m_dwPosition % (rcClient.right - rcClient.left + dwChunksWidth);
|
|
int nPosition = (int)dwPosition - (int)dwChunksWidth;
|
|
RECT rcChunk;
|
|
rcChunk.left = rcClient.left + nPosition + nCXEdge;
|
|
rcChunk.top = rcClient.top + nCYEdge;
|
|
rcChunk.bottom = rcClient.bottom - nCYEdge;
|
|
szChunk.cx -= 2 * nCXEdge;
|
|
for (DWORD dwChunkNum = 0; dwChunkNum < m_dwNumChunks; ++dwChunkNum)
|
|
{
|
|
rcChunk.right = rcChunk.left + szChunk.cx;
|
|
if (rcClip.left <= rcChunk.right && rcChunk.left < rcClip.right)
|
|
FillRect(hdcMem, &rcChunk, brushHighlight);
|
|
rcChunk.left = rcChunk.right + nCXEdge;
|
|
}
|
|
}
|
|
|
|
#ifdef USE_MEM_DC
|
|
BitBlt(hdc, prcPaint->left, prcPaint->top, nClientWidth, nClientHeight, hdcMem, prcPaint->left, prcPaint->top, SRCCOPY);
|
|
SelectBitmap(hdcMem, hbmpSafe);
|
|
DeleteDC(hdcMem);
|
|
DeleteBitmap(hbmpMem);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* @param hwnd - window handle.
|
|
* @param uMsg - message identifier.
|
|
* @param wParam - first message parameter.
|
|
* @param lParam - second message parameter.
|
|
*/
|
|
LRESULT CALLBACK CAnimProgressBar::AnimProgressBarWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
|
|
CAnimProgressBar* _this = (CAnimProgressBar*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
_ASSERTE(_this != NULL);
|
|
switch(uMsg)
|
|
{
|
|
case WM_ERASEBKGND:
|
|
return TRUE;
|
|
case WM_PAINT:
|
|
hdc = (HDC)wParam;
|
|
if (! hdc)
|
|
{
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
if (hdc)
|
|
{
|
|
_this->DrawAnimProgressBar(hdc, &ps.rcPaint);
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
}
|
|
else
|
|
_this->DrawAnimProgressBar(hdc, NULL);
|
|
return 0;
|
|
case WM_PRINTCLIENT:
|
|
hdc = (HDC)wParam;
|
|
_this->DrawAnimProgressBar(hdc, NULL);
|
|
return 0;
|
|
case WM_TIMER:
|
|
if (! _this->m_bActive)
|
|
return 0;
|
|
++_this->m_dwPosition;
|
|
RedrawWindow(_this->m_hwnd, NULL, NULL, RDW_INVALIDATE);
|
|
return 0;
|
|
case WM_DESTROY:
|
|
_this->Stop();
|
|
return 0;
|
|
case WM_NCHITTEST:
|
|
return HTTRANSPARENT;
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
}
|