|
|
//////////////////////////////////////////////////////////////////////////////
//
// ANIMATE.CPP
//
/*
This class is responsible for the animations in the busy dialogs such as the merge index dialog.
REVIEW: Could we use the commctrl animation control instead?
*/
// needed for those pesky pre-compiled headers
#include "header.h"
#include <windows.h>
#include "animate.h" // Animate class
#include "resource.h"
#ifdef _DEBUG
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__; #endif
static const char txtAnimateClassName[] = "Help_Animation"; static const WCHAR wtxtAnimateClassName[] = L"Help_Animation";
typedef struct { int left; int top; int cx; int cy; } WRECT;
void STDCALL GetWindowWRect(HWND hwnd, WRECT* prc) { ASSERT(IsValidWindow(hwnd)); GetWindowRect(hwnd, (PRECT) prc);
// Convert right and bottom into width and height
prc->cx -= prc->left; prc->cy -= prc->top; }
const int CX_DRAWAREA = 40; const int CY_DRAWAREA = 40;
const int CX_BOOK = 36; const int CY_BOOK = 36; const int C_BOOKS = 5; const int X_BOOK = 0; const int Y_BOOK = (CY_DRAWAREA - CY_BOOK);
const int CX_PEN = 15; const int CY_PEN = 20; const int C_PENS = 3; const int X_PEN = 18; const int Y_PEN = 2;
const int CX_STROKE = 1; const int CY_STROKE = 2;
const int C_HORZ_STROKES = 10; const int C_VERT_STROKES = 4; const int C_PEN_STROKES = (C_HORZ_STROKES * C_VERT_STROKES);
const int C_PAUSE_FRAMES = 0; const int C_FRAMES = (C_PEN_STROKES + C_BOOKS + C_PAUSE_FRAMES);
const int ANIMATE_INCREMENTS = 100;
const COLORREF clrPenA = RGB(128, 128, 128); const COLORREF clrPenB = RGB(128, 0, 128);
const int MAX_CNT_LINE = 1024; const int VPAD = 62; const int HPAD = 30;
static VOID _fastcall PointFromStroke(int xStroke, int yStroke, POINT* lppt);
#define SafeDeleteDC( hDC ) if( hDC ) { DeleteDC( hDC ); hDC = NULL; }
#define SafeDeleteObject( hObj ) if( hObj ) { DeleteObject( hObj ); hObj = NULL; }
LRESULT CALLBACK StatusWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // remove escape keys
#if 0
MSG msg2; if( PeekMessage( &msg2, hwnd, 0, 0, PM_NOREMOVE ) ) { if( msg2.message == WM_KEYDOWN || msg2.message == WM_KEYUP ) { if( msg2.wParam == VK_ESCAPE ) { PeekMessage( &msg2, hwnd, 0, 0, PM_REMOVE ); } } } #endif
if(g_bWinNT5) return DefWindowProcW(hwnd, msg, wParam, lParam); else return DefWindowProc(hwnd, msg, wParam, lParam); }
class Animate { public: Animate(); ~Animate(void); void STDCALL NextFrame(void); void SetPosition(int x, int y) { m_xPos = x; m_yPos = y; }; BOOL STDCALL CreateStatusWindow(HWND hwndParent, int idTitle); HWND m_hWndParent; HWND m_hWnd;
protected: HBITMAP m_hBmpTemp; HDC m_hDCBmp; HBITMAP m_hBmpIml; int m_iFrame; int m_xPos; int m_yPos; DWORD m_oldTickCount; DWORD m_originalTickCount; BOOL m_fShown; };
static Animate* g_pAnimationWindow = NULL;
BOOL STDCALL StartAnimation(int idTitle, HWND hWnd ) { ASSERT(!g_pAnimationWindow); if( g_pAnimationWindow ) return FALSE; g_pAnimationWindow = new Animate(); if( !hWnd ) if( !(hWnd = GetActiveWindow()) ) hWnd = GetDesktopWindow(); if (!g_pAnimationWindow->CreateStatusWindow( hWnd, idTitle)) { delete g_pAnimationWindow; g_pAnimationWindow = NULL; return FALSE; } return TRUE; }
void STDCALL NextAnimation(void) { if (g_pAnimationWindow) g_pAnimationWindow->NextFrame(); }
void STDCALL StopAnimation(void) { if (g_pAnimationWindow) delete g_pAnimationWindow; g_pAnimationWindow = NULL; }
BOOL STDCALL Animate::CreateStatusWindow(HWND hWndParent, int idTitle) { int width;
WORD lang = PRIMARYLANGID(_Module.m_Language.GetUiLanguage());
if(g_bWinNT5) { WNDCLASSW wc;
SIZE sSize;
ZeroMemory(&wc, sizeof(wc));
// Register Main window class
wc.hInstance = _Module.GetModuleInstance(); wc.style = CS_BYTEALIGNWINDOW | CS_CLASSDC; wc.lpfnWndProc = StatusWndProc; wc.lpszClassName = wtxtAnimateClassName; wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.hIcon = LoadIcon(_Module.GetResourceInstance(), "Icon!HTMLHelp");
if (!RegisterClassW(&wc)) return FALSE;
WRECT rc; m_hWndParent = hWndParent; GetWindowWRect(m_hWndParent, &rc);
const WCHAR *psz = GetStringResourceW(idTitle); int len = wcslen(psz); HDC hdc = GetDC(hWndParent); GetTextExtentPoint32W(hdc, psz, len, (LPSIZE)&sSize); ReleaseDC(m_hWndParent, hdc);
width = sSize.cx; if(lang == LANG_JAPANESE || lang == LANG_CHINESE || lang == LANG_KOREAN) width+=100;
if (width < CX_BOOK) width = CX_BOOK; if ( 0 /*!fIsThisNewShell4*/ ) width += HPAD;
#ifdef BIDI
m_hWnd = CreateWindowExW(WS_EX_WINDOWEDGE | /* WS_EX_TOPMOST | */ (fForceLtr ? 0 : WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR), wtxtAnimateClassName, psz, WS_POPUP | WS_BORDER | WS_CAPTION, rc.left + rc.cx / 2 - width / 2, rc.top + rc.cy / 2 - CY_BOOK / 2 + HPAD, width + GetSystemMetrics(SM_CXBORDER) * 2 + 2, CY_BOOK + GetSystemMetrics(SM_CYBORDER) * 2 + VPAD + GetSystemMetrics(SM_CYCAPTION), (IsWindowVisible(m_hWndParent)) ? m_hWndParent : NULL, NULL, hInsNow, NULL); #else
m_hWnd = CreateWindowExW(WS_EX_WINDOWEDGE /* | WS_EX_TOPMOST*/, wtxtAnimateClassName, psz, WS_POPUP | WS_BORDER | WS_CAPTION, rc.left + rc.cx / 2 - width / 2, rc.top + rc.cy / 2 - CY_BOOK / 2 + HPAD, width + GetSystemMetrics(SM_CXBORDER) * 2 + 2, CY_BOOK + GetSystemMetrics(SM_CYBORDER) * 2 + VPAD + GetSystemMetrics(SM_CYCAPTION), (IsWindowVisible(m_hWndParent)) ? m_hWndParent : NULL, NULL, _Module.GetModuleInstance(), NULL); #endif
} else { WNDCLASS wc; SIZE sSize;
ZeroMemory(&wc, sizeof(wc));
// Register Main window class
wc.hInstance = _Module.GetModuleInstance(); wc.style = CS_BYTEALIGNWINDOW | CS_CLASSDC; wc.lpfnWndProc = StatusWndProc; wc.lpszClassName = (LPCSTR) txtAnimateClassName; wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wc.hIcon = LoadIcon(_Module.GetResourceInstance(), "Icon!HTMLHelp");
if (!RegisterClass(&wc)) return FALSE;
WRECT rc; m_hWndParent = hWndParent; GetWindowWRect(m_hWndParent, &rc);
HDC hdc = GetDC(m_hWndParent); PSTR psz = (PSTR) GetStringResource(idTitle); GetTextExtentPoint32(hdc, psz, (int)strlen(psz), (LPSIZE)&sSize); width = sSize.cx; if(lang == LANG_JAPANESE || lang == LANG_CHINESE || lang == LANG_KOREAN) width+=100; if (width < CX_BOOK) width = CX_BOOK; if ( 0 /*!fIsThisNewShell4*/ ) width += HPAD; ReleaseDC(m_hWndParent, hdc);
#ifdef BIDI
m_hWnd = CreateWindowEx(WS_EX_WINDOWEDGE | /* WS_EX_TOPMOST | */ (fForceLtr ? 0 : WS_EX_RIGHT | WS_EX_RTLREADING | WS_EX_LEFTSCROLLBAR), (LPCSTR) txtAnimateClassName, psz, WS_POPUP | WS_BORDER | WS_CAPTION, rc.left + rc.cx / 2 - width / 2, rc.top + rc.cy / 2 - CY_BOOK / 2 + HPAD, width + GetSystemMetrics(SM_CXBORDER) * 2 + 2, CY_BOOK + GetSystemMetrics(SM_CYBORDER) * 2 + VPAD + GetSystemMetrics(SM_CYCAPTION), (IsWindowVisible(m_hWndParent)) ? m_hWndParent : NULL, NULL, hInsNow, NULL); #else
m_hWnd = CreateWindowEx(WS_EX_WINDOWEDGE /* | WS_EX_TOPMOST*/, (LPCSTR) txtAnimateClassName, psz, WS_POPUP | WS_BORDER | WS_CAPTION, rc.left + rc.cx / 2 - width / 2, rc.top + rc.cy / 2 - CY_BOOK / 2 + HPAD, width + GetSystemMetrics(SM_CXBORDER) * 2 + 2, CY_BOOK + GetSystemMetrics(SM_CYBORDER) * 2 + VPAD + GetSystemMetrics(SM_CYCAPTION), (IsWindowVisible(m_hWndParent)) ? m_hWndParent : NULL, NULL, _Module.GetModuleInstance(), NULL); #endif
} ASSERT(m_hWnd); SetPosition((width - CX_BOOK) / 2, VPAD / 4);
EnableWindow( m_hWndParent, FALSE );
if (!m_hWnd) { UnregisterClass((LPCSTR)txtAnimateClassName, _Module.GetModuleInstance()); return FALSE; }
m_fShown = FALSE; return TRUE; }
///////////////////////////// ANIMATE CLASS ///////////////////////////////
Animate::Animate() { m_hDCBmp = NULL; m_hWnd = NULL; m_originalTickCount = GetTickCount(); m_hWndParent = NULL; m_hBmpTemp = NULL; m_hBmpIml = NULL; }
Animate::~Animate(void) { SafeDeleteDC( m_hDCBmp ) SafeDeleteObject( m_hBmpTemp ); SafeDeleteObject( m_hBmpIml );
EnableWindow( m_hWndParent, TRUE );
if (m_hWnd) { DestroyWindow(m_hWnd); m_hWnd = NULL; UnregisterClass((LPCSTR) txtAnimateClassName, _Module.GetModuleInstance()); } }
/***************************************************************************
FUNCTION: AnimFrame
PURPOSE: Displays one frame of the "build index" animation in the specified device context.
PARAMETERS: hdc x y
RETURNS:
COMMENTS:
MODIFICATION DATES: 04-Nov-1993 [niklasb]
***************************************************************************/
void PASCAL Animate::NextFrame(void) { DWORD curTickCount = GetTickCount(); if (curTickCount - m_oldTickCount < ANIMATE_INCREMENTS) return; m_oldTickCount = curTickCount;
// Delay showing the window for one second. If we get done before then,
// then there's no need to have gone to all the trouble.
if (!m_fShown) { if (curTickCount - m_originalTickCount < 1000) return;
HBITMAP hbmBooks = LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDBMP_BOOK)); HBITMAP hbmPens = LoadBitmap(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDBMP_PENS)); HDC hdcTemp = CreateCompatibleDC(NULL); m_hDCBmp = CreateCompatibleDC(NULL);
HBITMAP hbmpOldBook = NULL; m_hBmpTemp = NULL; if (m_hDCBmp) { hbmpOldBook = (HBITMAP)SelectObject(m_hDCBmp, hbmBooks); m_hBmpTemp = CreateCompatibleBitmap(m_hDCBmp, CX_DRAWAREA, CY_DRAWAREA); }
if (!hbmBooks || !hbmPens || !m_hBmpTemp || !m_hDCBmp || !hdcTemp) { if (hbmpOldBook) SelectObject(m_hDCBmp, hbmpOldBook); SafeDeleteObject( hbmpOldBook ); SafeDeleteObject( hbmBooks ); SafeDeleteObject( hbmPens ); SafeDeleteDC( hdcTemp ); return; }
m_hBmpIml = CreateCompatibleBitmap(m_hDCBmp, CX_DRAWAREA * C_FRAMES, CY_DRAWAREA);
HBITMAP hbmpOldTemp = (HBITMAP) SelectObject(hdcTemp, m_hBmpTemp); HBITMAP hbmpOldBmp = (HBITMAP) SelectObject(m_hDCBmp, hbmBooks);
// Create the frames in which the pen scribbles on the open book.
m_iFrame = 0; for (int y = 0; y < C_VERT_STROKES; y++) { for (int x = 0; x < C_HORZ_STROKES; x++) {
// Show the book on a white background.
PatBlt(hdcTemp, 0, 0, CX_DRAWAREA, CY_DRAWAREA, WHITENESS); SelectObject(m_hDCBmp, hbmBooks);
BitBlt(hdcTemp, X_BOOK, Y_BOOK, CX_BOOK, CY_BOOK, m_hDCBmp, (C_BOOKS - 1) * CX_BOOK, 0, SRCCOPY);
// Add in the scribbled "text".
POINT pt; for (int yDraw = 0; yDraw < y; yDraw++) { for (int xDraw = 0; xDraw < C_HORZ_STROKES; xDraw++) { PointFromStroke(xDraw, yDraw, &pt); SetPixel(hdcTemp, pt.x, pt.y + CY_PEN - 1, (xDraw & 1) ? clrPenA : clrPenB); } } for (int xDraw = 0; xDraw <= x; xDraw++) { PointFromStroke(xDraw, y, &pt); SetPixel(hdcTemp, pt.x, pt.y + CY_PEN - 1, (xDraw & 1) ? clrPenA : clrPenB); }
// Add in the pen using the SRCAND operation.
SelectObject(m_hDCBmp, hbmPens); BitBlt(hdcTemp, pt.x, pt.y, CX_PEN, CY_PEN, m_hDCBmp, (m_iFrame & 1) ? CX_PEN : (m_iFrame & 2) * CX_PEN, 0, SRCAND);
SelectObject(m_hDCBmp, m_hBmpIml); BitBlt(m_hDCBmp, m_iFrame * CX_DRAWAREA, 0, CX_DRAWAREA, CY_DRAWAREA, hdcTemp, 0, 0, SRCCOPY);
m_iFrame++; } }
// Blast a white background into the temporary bitmap, and
// select the books bitmap.
PatBlt(hdcTemp, 0, 0, CX_DRAWAREA, CY_DRAWAREA, WHITENESS);
// Add the frames for the page turning (from the books bitmap).
for (int iBook = 0; iBook < C_BOOKS; iBook++) { SelectObject(m_hDCBmp, hbmBooks); BitBlt(hdcTemp, X_BOOK, Y_BOOK, CX_BOOK, CY_BOOK, m_hDCBmp, iBook * CX_BOOK, 0, SRCCOPY); SelectObject(m_hDCBmp, m_hBmpIml); BitBlt(m_hDCBmp, m_iFrame * CX_DRAWAREA, 0, CX_DRAWAREA, CY_DRAWAREA, hdcTemp, 0, 0, SRCCOPY); m_iFrame++; }
SelectObject(hdcTemp, hbmpOldTemp);
m_iFrame = 0;
if (hbmpOldBook) SelectObject(m_hDCBmp, hbmpOldBook); SafeDeleteObject(hbmpOldBook); SafeDeleteObject(hbmBooks); SafeDeleteObject(hbmPens); SafeDeleteDC( hdcTemp );
m_fShown = TRUE; ShowWindow(m_hWnd, SW_NORMAL);
}
ASSERT(IsValidWindow(m_hWnd)); HDC hdc = GetDC(m_hWnd); HBITMAP hbmpOld = (HBITMAP) SelectObject(m_hDCBmp, m_hBmpIml); BitBlt(hdc, m_xPos, m_yPos, CX_DRAWAREA, CY_DRAWAREA, m_hDCBmp, m_iFrame * CX_DRAWAREA, 0, SRCCOPY); SelectObject(m_hDCBmp, hbmpOld);
ReleaseDC(m_hWnd, hdc);
// Next time draw the next frame.
if (++m_iFrame > C_FRAMES) { m_iFrame = 0; } }
static VOID FASTCALL PointFromStroke(int xStroke, int yStroke, POINT* lppt) { int cx = (C_HORZ_STROKES / 2) - xStroke;
lppt->x = X_PEN + xStroke * CX_STROKE; lppt->y = Y_PEN + yStroke * CY_STROKE + cx * cx / 10; }
|