#include #include #include "resource.h" #include "dibutil.h" #include "billbrd.h" #include "animate.h" #define MAX_ANIMSTRING MAX_STRING #define MyWait(c) {int __nCnt = (c); while(__nCnt) __nCnt--;} #define GetInvertRGB(rgb) (RGB(255 - GetRValue(rgb), 255 - GetGValue(rgb), 255 - GetBValue(rgb))) #define CX_MOVE 4 #define CY_MOVE 4 #define CX_SHADOW 4 #define CY_SHADOW 4 #define FONT_TITLE 0 #define FONT_TEXT 1 #define FONT_DELETE 10 // AnimateBlt Index #define AB_HOR_POS 1 #define AB_HOR_NEG 2 #define AB_VER_POS 3 #define AB_VER_NEG 4 typedef struct _tagANISTRINGFORM { COLORREF col; BOOL bShadow; COLORREF colShadow; RECT rc; UINT uiLineHeightx2; HFONT hFont; } ANISTRINGFORM, FAR *LPANISTRINGFORM; HDC g_hdcCache = NULL; HBITMAP g_hbmp = NULL; HBITMAP g_hbmpOldCache = NULL; LOGFONT g_lfTemp = {0}; BOOL g_fBullet = FALSE; UINT g_uiAnimateIndex = (UINT)-1; UINT g_uiLastAnimateIndex = (UINT)-1; void RestoreCachedRect() { HWND hwndBB; HDC hdcBB; int cxBB; int cyBB; RECT rcBB; hwndBB = GetBBHwnd(); if (GetClientRect(hwndBB, &rcBB)) { cxBB = rcBB.right - rcBB.left; cyBB = rcBB.bottom - rcBB.top; hdcBB = GetDC(hwndBB); if (hdcBB) { // Init cached bitmap BitBlt(hdcBB, 0, 0, cxBB, cyBB, g_hdcCache, 0, 0, SRCCOPY); ReleaseDC(hwndBB, hdcBB); } } } void AnimateBlt(HDC hdcDest, int x, int y, int w, int h, HDC hdcSrc, int xSrc, int ySrc, int nPattern) { int i; switch (nPattern) { case AB_HOR_POS: for (i = 0; i < w; i++) { BitBlt(hdcDest, x + i, y, 1, h, hdcSrc, xSrc + i, ySrc, SRCCOPY); MyWait(10000); } break; case AB_VER_POS: for (i = 0; i < h; i++) { BitBlt(hdcDest, x, y + 1, w, 1, hdcSrc, xSrc + i, ySrc, SRCCOPY); MyWait(10000); } break; } } void RestoreRect(HDC hdc, LPRECT lprc, int nPat) { int cx = lprc->right - lprc->left + 1; int cy = lprc->bottom - lprc->top + 1; if (hdc) { BitBlt(hdc, lprc->left, lprc->top, cx, cy, g_hdcCache, lprc->left, lprc->top, SRCCOPY); } } /********************************************************************** * CheckForBulletAndRemoveMarker() * * This function checks if the line of text has a bullet preceding it * if so it removes the bullet identifier from the string. This function * also sets the value of piWidth to the width of the bitmap. * * Returns: TRUE == Bullet needed * FALSE == No bullet * **********************************************************************/ BOOL CheckForBulletAndRemoveMarker(LPTSTR lpstr, LPINT lpiWidth) { BOOL bRet = FALSE; LPTSTR p = NULL; HBITMAP hBmp = NULL; BITMAP bm; p = lpstr; *lpiWidth = 0; g_fBullet = FALSE; if(*p) { while(*p == TEXT(' ')) p = CharNext(p); if(*p == '-') { lstrcpy(p, CharNext(p)); bRet = TRUE; hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BULLET_1)); GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bm); *lpiWidth = bm.bmWidth; DeleteObject(hBmp); g_fBullet = TRUE; } } return bRet; } /********************************************************************** * CheckForBulletAndReturnWidth() * * This function checks if the line of text has a bullet preceding it * if so figures out the bullet bitmaps width and returns it. * * Returns: TRUE == Bullet needed * FALSE == No bullet * **********************************************************************/ int CheckForBulletAndReturnWidth(LPTSTR lpstr) { int iWidth = 0; LPTSTR p = NULL; HBITMAP hBmp = NULL; BITMAP bm; p = lpstr; if(*p) { while(*p == TEXT(' ')) p = CharNext(p); if(*p == TEXT('-')) { hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BULLET_1)); GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bm); iWidth = bm.bmWidth; DeleteObject(hBmp); } } return iWidth; } /********************************************************************** * PaintBulletIfNeeded() * * This function checks if the line of text needs a bullet to be painted * if so paints the bullet bitmap on the given coords on the given dc. * * Returns: None * **********************************************************************/ void PaintBulletIfNeeded(HDC hdc, int x, int y , int iHeight) { HBITMAP hBmp = NULL; BITMAP bm; if(g_fBullet) { hBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_BULLET_1)); if(hBmp) { GetObject(hBmp, sizeof(BITMAP), &bm); DrawBitmap(hdc, hBmp, x, y + (iHeight - bm.bmHeight)/2); DeleteObject(hBmp); g_fBullet = FALSE; } } } void GetPanelSectionName(int nPanel, LPTSTR lpszKey) { wsprintf(lpszKey, TEXT("Panel%d"), nPanel); } int GetTextCount(int nPanel) { TCHAR szKey[80]; GetPanelSectionName(nPanel, szKey); return GetPrivateProfileInt(szKey, TEXT("Count"), 0, g_szFileName); } int GetTitle(int nPanel, LPTSTR lpStr) { TCHAR szKey[80]; GetPanelSectionName(nPanel, szKey); return GetPrivateProfileString(szKey, TEXT("Title"), TEXT(""), lpStr, MAX_ANIMSTRING, g_szFileName); } int GetPanelText(int nPanel, int nCnt, LPTSTR lpStr) { TCHAR szKey[16]; TCHAR szSec[16]; GetPanelSectionName(nPanel, szKey); wsprintf(szSec, TEXT("Text%d"), nCnt); return GetPrivateProfileString(szKey, szSec, TEXT(""), lpStr, MAX_ANIMSTRING, g_szFileName); } BOOL CALLBACK GetLogFontEnumProc(LPLOGFONT lplf, LPTEXTMETRIC lptm, int wType, LPARAM lpData) { g_lfTemp = *lplf; return 0; } BOOL GetLogFontFromFaceName(LPLOGFONT lplf, LPTSTR lpszFaceName) { HWND hwndBB = NULL; HDC hdcBB = NULL; FONTENUMPROC lpEnumFontsCallBack = NULL; hwndBB = GetBBHwnd(); hdcBB = GetDC(hwndBB); lpEnumFontsCallBack = (FONTENUMPROC)MakeProcInstance((FARPROC)GetLogFontEnumProc, g_hInstance); EnumFonts((HDC)hdcBB, (LPCTSTR)lpszFaceName, (FONTENUMPROC)lpEnumFontsCallBack, 0L); FreeProcInstance((FARPROC)lpEnumFontsCallBack); *lplf = g_lfTemp; ReleaseDC(hwndBB, hdcBB); return TRUE; } /********************************************************************** * GetDeleteFontHandle() * * This function checks if the font specified by iFontnum exists already. * if so returns its handle if not it creates the font and return the * handle. returns NULL in error case. if Function is called with * iFontNum = FONT_DELETE then the existing fonts are deleted. * * INPUT: iFontNum * Returns: HFONT * * 10/08/97 hanumany created **********************************************************************/ HFONT GetDeleteFontHandle(int iFontNum) { static HFONT hFontTitle = NULL; static HFONT hFontText = NULL; switch(iFontNum) { case FONT_TITLE: { if(hFontTitle) { return hFontTitle; } else { LOGFONT lf = {0}; GetLogFontFromFaceName(&lf, g_szTFont); lf.lfHeight = -MulDiv(g_nTFontHeight, 96, 72); lf.lfWidth = g_nTFontWidth; lf.lfWeight = g_nTFontWeight; lf.lfQuality = ANTIALIASED_QUALITY; lf.lfCharSet = g_bCharSet; hFontTitle = CreateFontIndirect(&lf); return hFontTitle; } } case FONT_TEXT: { if(hFontText) { return hFontText; } else { LOGFONT lf = {0}; GetLogFontFromFaceName(&lf, g_szBFont); lf.lfHeight = -MulDiv(g_nBFontHeight, 96, 72); lf.lfWidth = g_nBFontWidth; lf.lfWeight = g_nBFontWeight; lf.lfQuality = PROOF_QUALITY; lf.lfCharSet = g_bCharSet; hFontText = CreateFontIndirect(&lf); return hFontText; } } case FONT_DELETE: { if(hFontTitle) { DeleteObject(hFontTitle); hFontTitle = NULL; } if(hFontText) { DeleteObject(hFontText); hFontText = NULL; } break; } } return NULL; } /************************************************************************ * RemoveLineBreakChar() * * This function copies lpszCurr to lpszFixed without the line break char's * ************************************************************************/ void RemoveLineBreakChar(LPCTSTR lpszCurr, LPTSTR lpszFixed) { while (*lpszCurr != TEXT('\0')) { if(*lpszCurr != TEXT('|')) { *lpszFixed = *lpszCurr; #ifndef UNICODE if(IsDBCSLeadByte(*lpszFixed)) { *(lpszFixed+1) = *(lpszCurr+1); } #endif lpszFixed = CharNext(lpszFixed); lpszCurr = CharNext(lpszCurr); } else { lpszCurr = CharNext(lpszCurr); } } *lpszFixed = '\0'; return; } void MergeBlt(LPTSTR lpstr, HDC hdcDst, int x0, int y0, int cx0, int cy0, HDC hdcSrc, int x1, int y1, int cx1, int cy1, COLORREF rgb, COLORREF rgbShadow, BOOL fShadow, BOOL fStretch, TEXTMETRIC* lptm, int iLineSpace, RECT* lprc ) { int nNumLines = 0; if (fShadow) { SetTextColor(hdcSrc, 0); DisplayString(hdcSrc, x1 + CX_SHADOW, y1 + CY_SHADOW, lptm, iLineSpace, lprc, &nNumLines, lpstr, LEFT); if (fStretch) { StretchBlt(hdcDst, x0, 0, cx0, cy0, hdcSrc, x1, y1, cx1, cy1, SRCAND); } else { BitBlt(hdcDst, x0, 0, cx0, cy0, hdcSrc, x1, y1, SRCAND); } SetTextColor(hdcSrc, GetInvertRGB(rgbShadow)); DisplayString(hdcSrc, x1 + CX_SHADOW, y1 + CY_SHADOW, lptm, iLineSpace, lprc, &nNumLines, lpstr, LEFT); if (fStretch) { StretchBlt(hdcDst, y0, y0, cx0, cy0, hdcSrc, x1, y1, cx1, cy1, MERGEPAINT); } else { BitBlt(hdcDst, y0, y0, cx0, cy0, hdcSrc, x1, y1, MERGEPAINT); } } SetTextColor(hdcSrc, 0); DisplayString(hdcSrc, x1, y1, lptm, iLineSpace, lprc, &nNumLines, lpstr, LEFT); if (fStretch) { StretchBlt(hdcDst, x0, 0, cx0, cy0, hdcSrc, x1, y1, cx1, cy1, SRCAND); } else { BitBlt(hdcDst, x0, 0, cx0, cy0, hdcSrc, x1, y1, SRCAND); } SetTextColor(hdcSrc, GetInvertRGB(rgb)); DisplayString(hdcSrc, x1, y1, lptm, iLineSpace, lprc, &nNumLines, lpstr, LEFT); if (fStretch) { StretchBlt(hdcDst, y0, y0, cx0, cy0, hdcSrc, x1, y1, cx1, cy1, MERGEPAINT); } else { BitBlt(hdcDst, y0, y0, cx0, cy0, hdcSrc, x1, y1, MERGEPAINT); } } int AnimateString( HDC hdc, LPTSTR lpstr, LPANISTRINGFORM lpani, int iLineSpace, int nPat ) { HWND hwndBB = NULL; int cxBB; int cyBB; RECT rcBB; HDC hdcMem = NULL; HDC hdcText = NULL; HBITMAP hbmpMem = NULL; HBITMAP hbmpText = NULL; HBITMAP hbmpOld = NULL; HBITMAP hbmpOldText = NULL; HFONT hfont = NULL; HFONT hfontOld = NULL; HBRUSH hbrBlack = NULL; HBRUSH hbrWhite = NULL; HBRUSH hbrOldText = NULL; int cx; int cy; int i,j; TEXTMETRIC tm; int x0; int nLen; int nWait; int nDelta; RECT rc; int nNumLines = 0; int ibmWidth = 0; SIZE size; hwndBB = GetBBHwnd(); if (!GetClientRect(hwndBB, &rcBB)) { goto exit; } cxBB = rcBB.right - rcBB.left; cyBB = rcBB.bottom - rcBB.top; hbrWhite = GetStockObject(WHITE_BRUSH); if (hbrWhite == NULL) { goto exit; } hbrBlack = GetStockObject(BLACK_BRUSH); if (!hbrBlack) { goto exit; } hdcText = CreateCompatibleDC(hdc); if (!hdcText) { goto exit; } hbmpText = CreateCompatibleBitmap(hdc, cxBB, cyBB); if (!hbmpText) { goto exit; } hdcMem = CreateCompatibleDC(hdc); if (!hdcMem) { goto exit; } cx = lpani->rc.right - lpani->rc.left + 1; cy = lpani->rc.bottom - lpani->rc.top + 1; if (lpani->bShadow) { cx += CX_SHADOW; cy += CY_SHADOW; } hbmpMem = CreateCompatibleBitmap(hdc, cxBB, cyBB); if (!hbmpMem) { goto exit; } hbmpOld = SelectObject(hdcMem, hbmpMem); SetBkMode(hdcMem, TRANSPARENT); hfont = lpani->hFont; if (!hfont) { goto exit; } hfontOld = SelectObject(hdcMem, hfont); GetTextMetrics(hdcMem, &tm); nLen = lstrlen(lpstr); GetTextExtentPoint32(hdcMem, lpstr, nLen, &size); ibmWidth = CheckForBulletAndReturnWidth(lpstr); if (cx > (int)size.cx + ibmWidth + 10) { cx = (int)size.cx + ibmWidth + 10; } if (cy > (int)size.cy) { cy = (int)size.cy; } hfontOld = SelectObject(hdcText, hfont); hbmpOldText = SelectObject(hdcText, hbmpText); hbrOldText = SelectObject(hdcText, hbrWhite); rc.left = 0; rc.top = 0; rc.right = cx; rc.bottom = cy; FillRect(hdcText, &rc, hbrWhite); DisplayString(hdcText, 0, 0, &tm, iLineSpace, &rc, &nNumLines, lpstr, LEFT); if(nNumLines > 1) { cy = cy + (tm.tmHeight * lpani->uiLineHeightx2 * nNumLines / 2); rc.left = 0; rc.top = 0; rc.right = cx; rc.bottom = cy; FillRect(hdcText, &rc, hbrWhite); DisplayString(hdcText, 0, 0, &tm, iLineSpace, &rc, &nNumLines, lpstr, LEFT); } switch (nPat) { default: case 7: case 0: { COLORREF crOld = 0; if (g_bBiDi) { BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.right-cx, lpani->rc.top, SRCCOPY); } else { BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); } if (lpani->bShadow) { CONST int SHADOW_OFFSET = 2; RECT rcShadow; if (SetRect(&rcShadow, rc.left, rc.top, rc.right + SHADOW_OFFSET, rc.bottom + SHADOW_OFFSET)) { crOld = SetTextColor(hdcMem, lpani->colShadow); DisplayString(hdcMem, SHADOW_OFFSET, SHADOW_OFFSET, &tm, iLineSpace, &rcShadow, &nNumLines, lpstr, LEFT); SetTextColor(hdcMem, crOld); } } crOld = SetTextColor(hdcMem, lpani->col); DisplayString(hdcMem, 0, 0, &tm, iLineSpace, &rc, &nNumLines, lpstr, LEFT); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); if (g_bBiDi) { BitBlt(hdc, lpani->rc.right-cx, lpani->rc.top - tm.tmInternalLeading, cx, cy, hdcMem, 0, 0, SRCCOPY); } else { BitBlt(hdc, lpani->rc.left, lpani->rc.top - tm.tmInternalLeading, cx, cy, hdcMem, 0, 0, SRCCOPY); } SetTextColor(hdcMem, crOld); break; } case 1: if (g_bBiDi) BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.right-cx, lpani->rc.top, SRCCOPY); else BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); for (i = 0; i < cy ; i+=4) { if (g_bBiDi) BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.right-cx, lpani->rc.top, SRCCOPY); else BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, i, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, TRUE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); if (g_bBiDi) BitBlt(hdc, lpani->rc.right-cx, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); else BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); MyWait(10000); } if (g_bBiDi) BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.right-cx, lpani->rc.top, SRCCOPY); else BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, FALSE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); if (g_bBiDi) BitBlt(hdc, lpani->rc.right-cx, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); else BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); break; case 2: DisplayString(hdcText, 0, 0, &tm, iLineSpace, &rc, &nNumLines, lpstr, LEFT); BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); for (i = 0; i < cx ; i+=4) { BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, i, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, TRUE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); MyWait(10000); } BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, FALSE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); break; case 3: nWait = 100; for (i = cxBB; i > lpani->rc.left; i -= CX_MOVE) { int xCur = i; BitBlt(hdc, xCur + cx, lpani->rc.top, CX_MOVE, cy, g_hdcCache, xCur + cx, lpani->rc.top, SRCCOPY); BitBlt(hdcMem, 0, 0, cxBB - xCur, cy, g_hdcCache, xCur, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, FALSE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, xCur, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); MyWait(nWait * nWait); nWait++; } BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, FALSE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); BitBlt(hdc, lpani->rc.left + cx, lpani->rc.top, CX_MOVE, cy, g_hdcCache, lpani->rc.left + cx, lpani->rc.top, SRCCOPY); break; case 4: nWait = 100; nDelta = (lpani->rc.right - lpani->rc.left) / 10; x0 = cxBB; while (abs(nDelta) > CX_MOVE) { for (i = x0; abs(i - (lpani->rc.left - nDelta)) > CX_MOVE; i -= (CX_MOVE * (nDelta/ abs(nDelta)))) { int xCur = i; BitBlt(hdc, xCur + cx, lpani->rc.top, CX_MOVE, cy, g_hdcCache, xCur + cx, lpani->rc.top, SRCCOPY); BitBlt(hdc, xCur - CX_MOVE, lpani->rc.top, CX_MOVE, cy, g_hdcCache, xCur - CX_MOVE, lpani->rc.top, SRCCOPY); BitBlt(hdcMem, 0, 0, cxBB - xCur, cy, g_hdcCache, xCur, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, FALSE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, xCur, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); MyWait(nWait * nWait); nWait++; } nDelta *= 2; nDelta /= 3; nDelta = 0 - nDelta; x0 = i; } BitBlt(hdcMem, 0, 0, cx, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); MergeBlt(lpstr, hdcMem, 0, 0, cx, cy, hdcText, 0, 0, cx, cy, lpani->col, lpani->colShadow, lpani->bShadow, FALSE, &tm, iLineSpace, &rc); PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); BitBlt(hdc, lpani->rc.left + cx, lpani->rc.top, CX_MOVE, cy, g_hdcCache, lpani->rc.left + cx, lpani->rc.top, SRCCOPY); break; case 5: BitBlt(hdcMem, 0, 0, cxBB - lpani->rc.left, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); DisplayString(hdcMem, 0, 0, &tm, iLineSpace, &rc, &nNumLines, lpstr, LEFT); for (i = 0; i < nLen; i++) { int nSize; int nNextSize; SIZE size; GetTextExtentPoint32(hdcMem, lpstr, i, &size); nSize = size.cx; GetTextExtentPoint32(hdcMem, lpstr, i+1, &size); nNextSize = size.cx - nSize; if (nSize + nNextSize > cx) break; PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, nSize, cy, hdcMem, 0, 0, SRCCOPY); BitBlt(hdc, lpani->rc.left + nSize, lpani->rc.top, CX_MOVE, cy, g_hdcCache, lpani->rc.left + nSize, lpani->rc.top, SRCCOPY); for (j = cxBB; j > lpani->rc.left+nSize ; j-=CX_MOVE) { int xCur = j; int xPrev = j + nNextSize; PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, xPrev, lpani->rc.top, CX_MOVE, cy, g_hdcCache, xPrev, lpani->rc.top, SRCCOPY); BitBlt(hdc, xCur, lpani->rc.top, nNextSize, cy, hdcMem, nSize, 0, SRCCOPY); MyWait(20000); } } PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); BitBlt(hdc, lpani->rc.left + cx, lpani->rc.top, CX_MOVE, cy, g_hdcCache, lpani->rc.left + cx, lpani->rc.top, SRCCOPY); break; case 6: BitBlt(hdcMem, 0, 0, cxBB - lpani->rc.left, cy, g_hdcCache, lpani->rc.left, lpani->rc.top, SRCCOPY); DisplayString(hdcMem, 0, 0, &tm, iLineSpace, &rc, &nNumLines, lpstr, LEFT); for (i = 0; i < nLen; i++) { int nSize; int nNextSize; SIZE size; GetTextExtentPoint32(hdcMem, lpstr, i, &size); nSize = size.cx; GetTextExtentPoint32(hdcMem, lpstr, i+1, &size); nNextSize = size.cx - nSize; if (nSize + nNextSize > cx) break; PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, nSize, cy, hdcMem, 0, 0, SRCCOPY); BitBlt(hdc, lpani->rc.left, lpani->rc.top - CY_MOVE, nSize, CY_MOVE, g_hdcCache, lpani->rc.left, lpani->rc.top - CY_MOVE, SRCCOPY); for (j = cyBB; j > lpani->rc.top; j-=CY_MOVE) { int yCur = j; int yPrev = j + cy; PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left+nSize, yPrev, nNextSize, CY_MOVE, g_hdcCache, lpani->rc.left+nSize, yPrev, SRCCOPY); BitBlt(hdc, lpani->rc.left+nSize, yCur, nNextSize, cy, hdcMem, nSize, 0, SRCCOPY); MyWait(20000); } } PaintBulletIfNeeded(hdcMem, 0, 0, tm.tmHeight); BitBlt(hdc, lpani->rc.left, lpani->rc.top, cx, cy, hdcMem, 0, 0, SRCCOPY); BitBlt(hdc, lpani->rc.left, lpani->rc.top + cy, cx, CY_MOVE, g_hdcCache, lpani->rc.left, lpani->rc.top + cy, SRCCOPY); break; } SelectObject(hdcMem, hbmpOld); SelectObject(hdcText, hbrOldText); SelectObject(hdcText, hbmpOldText); SelectObject(hdcText, hfontOld); SelectObject(hdcMem, hfontOld); exit: if (hbmpText) DeleteObject(hbmpText); if (hdcText) DeleteDC(hdcText); if (hbmpMem) DeleteObject(hbmpMem); if (hdcMem) DeleteDC(hdcMem); if (hbrWhite) { DeleteObject(hbrWhite); } if (hbrBlack) { DeleteObject(hbrBlack); } return nNumLines; } void AnimateNext() { if (g_uiAnimateIndex != (UINT)-1) { g_uiAnimateIndex++; if (bb_text[dwBBTextType][g_uiAnimateIndex].uiTitle == 0) g_uiAnimateIndex = 0; } } BOOL InitAnimate(HWND hwnd, HDC hdc) { int cxBB; int cyBB; RECT rcBB; HDC hdcMem; RECT rcBBToParent; BOOL retval = FALSE; if (GetClientRect(hwnd, &rcBB)) { cxBB = rcBB.right - rcBB.left; cyBB = rcBB.bottom - rcBB.top; if (g_hbmp) { SelectObject(g_hdcCache, g_hbmpOldCache); DeleteObject(g_hbmp); g_hbmp = NULL; } if (g_hdcCache) { DeleteDC(g_hdcCache); g_hdcCache = NULL; } g_hdcCache = CreateCompatibleDC(hdc); g_hbmp = CreateCompatibleBitmap(hdc, cxBB, cyBB); if (g_hdcCache && g_hbmp) { g_hbmpOldCache = SelectObject(g_hdcCache, g_hbmp); hdcMem = GetBackgroundBuffer(); GetRectInParent(hwnd, &rcBB, &rcBBToParent); retval = BitBlt(g_hdcCache, 0, 0, cxBB, cyBB, hdcMem, rcBBToParent.left, rcBBToParent.top, SRCCOPY); } } return retval; } void TerminateAnimate() { RestoreCachedRect(); if (g_hbmp) { SelectObject(g_hdcCache, g_hbmpOldCache); DeleteObject(g_hbmp); g_hbmp = NULL; } if (g_hdcCache) { DeleteDC(g_hdcCache); g_hdcCache = NULL; } GetDeleteFontHandle(FONT_DELETE); } /********************************************************************************* * * Animate() * * Main animation function. * *********************************************************************************/ void Animate(HDC hdc) { RECT rc; ANISTRINGFORM ani; int nPadBuffer, nLinePad, nWndHeight, nNumLines = 0; TCHAR sz[MAX_STRING]; TCHAR szText[MAX_STRING]; int iOldMapMode; if (g_uiAnimateIndex == (UINT)-1) return; if (!GetClientRect(GetBBHwnd(), &rc)) { return; } iOldMapMode = SetMapMode(hdc, MM_TEXT); if(g_nAnimID != 7) { RestoreRect(hdc, &rc, AB_HOR_POS); } rc.left = g_cxBillBrdHMargin; rc.top = g_cyBillBrdTitleTop; rc.right = g_cxBillBrdTitleWidth; rc.bottom = g_cyBillBrdHeight; nWndHeight = GetSystemMetrics(SM_CYSCREEN); nPadBuffer = nWndHeight / 80; // 6 pixels @ 640x480 nLinePad = nWndHeight / 80; // 6 pixels @ 640x480 ani.col = g_colTitle; ani.colShadow = g_colTitleShadow; ani.bShadow = g_bTitleShadow; ani.uiLineHeightx2 = 2; ani.rc.top = rc.top; ani.rc.bottom = rc.bottom; ani.rc.left = rc.left; ani.rc.right = rc.right; ani.hFont = GetDeleteFontHandle(FONT_TITLE); if (LoadString(g_hInstance, bb_text[dwBBTextType][g_uiAnimateIndex].uiTitle, (LPTSTR)sz, sizeof(sz)/sizeof(TCHAR))) { nNumLines = AnimateString(hdc, sz, &ani, 0, g_nAnimID); } rc.top += (g_nTFontHeight * 2 + nLinePad) * nNumLines; rc.right = g_cxBillBrdBodyWidth; if (LoadString(g_hInstance, bb_text[dwBBTextType][g_uiAnimateIndex].uiText, (LPTSTR)sz, sizeof(sz)/sizeof(TCHAR))) { UINT i = 0; // Process the string so that we can have paragraphs. // /r/n marks end of line // while (sz[i] != TEXT('\0')) { UINT j = 0; // see if the author has a hard line break // If, just give the line until the line break to display // The rest is done hte next time around. while ((sz[i] != TEXT('\0')) && (sz[i] != TEXT('\r')) && (sz[i] != TEXT('\n')) ) { szText[j] = sz[i]; j++; i++; } // if there is a line break character, skip this one. if (sz[i] != TEXT('\0')) i++; szText[j] = TEXT('\0'); ani.col = g_colText; ani.colShadow = g_colTextShadow; ani.bShadow = g_bTextShadow; ani.uiLineHeightx2 = 3; ani.rc.top = rc.top; ani.rc.bottom = rc.bottom; ani.rc.left = rc.left; ani.rc.right = rc.right; ani.hFont = GetDeleteFontHandle(FONT_TEXT); nNumLines = AnimateString(hdc, szText, &ani, g_nBLineSpace, g_nAnimID); if (*szText) { rc.top += (g_nBFontHeight * (100 + g_nBLineSpace) / 100 + nLinePad) * nNumLines; rc.bottom += (g_nBFontHeight * (100 + g_nBLineSpace) / 100 + nLinePad) * nNumLines; } else { rc.top += g_nBFontHeight * (100 + g_nBLineSpace) / 100 + nPadBuffer; rc.bottom += g_nBFontHeight * (100 + g_nBLineSpace) / 100 + nPadBuffer; } // assume that there are allways \r\n for one line break. Skip the other one if ((sz[i] != TEXT('\0')) && ((sz[i] == TEXT('\r')) || (sz[i] == TEXT('\n')) ) ) i++; } } SetMapMode(hdc, iOldMapMode); } /***************************************************************************************** * This function displays a text string on the given coordinates. It figures * out word wraping and distance between lines based on the font. the pNumLines * param is set to indicate the num of lines output after wrapping text(NULL if failed). * Returns The result from TextOut. *****************************************************************************************/ BOOL DisplayString( HDC hdc, int x, int y, TEXTMETRIC* lptm, int iLineSpace, RECT* lprc, LPINT pNumLines, LPTSTR szTextOut, WORD wfPlacement) { LPTSTR szWorkBuffer = NULL; BOOL ret = FALSE; int newX = 0; // The multiplication factor 2 handle the worst case scenario, in which // every character can have a line break followed by it, but no '|' // character is specified in the string. szWorkBuffer = (LPTSTR)HeapAlloc( GetProcessHeap(), 0, (lstrlen(szTextOut) + 1) * sizeof(TCHAR) * 2); if (szWorkBuffer) { lstrcpy(szWorkBuffer, szTextOut); if(CheckForBulletAndRemoveMarker(szWorkBuffer, &newX)) { newX += (x + 10); //leave space for the bullet bitmap } else { newX = x; } *pNumLines = WrapText(hdc, newX, lprc, szWorkBuffer); ret = DrawWrapText(hdc, lptm, iLineSpace, newX, y, lprc, wfPlacement, *pNumLines, szWorkBuffer); HeapFree(GetProcessHeap(), 0, szWorkBuffer); } return ret; } int WrapText( IN HDC hdc, IN int x, IN RECT* lprc, IN OUT LPTSTR szBBResource) { BOOL bDoneText = FALSE; int iNumLines = 0; LPTSTR pBBResource = szBBResource; LPTSTR szRemainedWords = NULL; TCHAR szCurrentLine[MAX_STRING]; TCHAR szCurrentLineWords[MAX_STRING]; LPTSTR pRemainedWords = NULL; LPTSTR pCurrentLineWords = NULL; LPTSTR pCurrentLine = NULL; SIZE sz; LONG uiRCWidth; szRemainedWords = (LPTSTR)HeapAlloc( GetProcessHeap(), 0, (lstrlen(szBBResource) + 1) * sizeof(TCHAR)); if(szRemainedWords) { lstrcpy(szRemainedWords, szBBResource); } else { return 0; } uiRCWidth = lprc->right - lprc->left - x; while(!bDoneText) { *szCurrentLine = TEXT('\0'); pCurrentLineWords = szCurrentLineWords; pRemainedWords = szRemainedWords; pCurrentLine = szCurrentLine; RemoveLineBreakChar(pRemainedWords, pCurrentLine); GetTextExtentPoint32(hdc, pCurrentLine, lstrlen(pCurrentLine), &sz); ZeroMemory( szCurrentLine , sizeof(szCurrentLine)); ZeroMemory( szCurrentLineWords , sizeof(szCurrentLineWords)); if(uiRCWidth >= sz.cx) { RemoveLineBreakChar(pRemainedWords, pCurrentLine); bDoneText = TRUE; } else { // break up string into displayable segment BOOL bDoneLine = FALSE; while(!bDoneLine) { BOOL bDoneWord = FALSE; while(!bDoneWord) { *pCurrentLineWords = TEXT('\0'); //null terminate for GetTextExtent GetTextExtentPoint32(hdc, szCurrentLineWords, lstrlen(szCurrentLineWords), &sz); if(*pRemainedWords == TEXT('|')) //Line break char (potential line break) { pRemainedWords = CharNext(pRemainedWords); bDoneWord = TRUE; } else if( *pRemainedWords == TEXT('\0')) //end of string { bDoneWord = TRUE; bDoneLine = TRUE; } else if((sz.cx + 2 >= uiRCWidth ) && (lstrcmp(szCurrentLine, TEXT("") ) == 0)) //if the word is too big to fit on one line then break out. Code outside this //loop will add a space in word and this will cause a line break. { bDoneWord = TRUE; } else { *pCurrentLineWords = *pRemainedWords; #ifndef UNICODE if(IsDBCSLeadByte(*pCurrentLineWords)) { *(pCurrentLineWords+1) = *(pRemainedWords+1); } #endif pCurrentLineWords = CharNext(pCurrentLineWords); pRemainedWords = CharNext(pRemainedWords); } } //Check if the current buffers extent is more than the width GetTextExtentPoint32(hdc, szCurrentLineWords, lstrlen(szCurrentLineWords), &sz); if((sz.cx >= uiRCWidth ) && (lstrcmp(szCurrentLine, TEXT("") ) != 0)) { //string is too big && saved str is not empty(use previously saved str) bDoneLine = TRUE; } else { *pCurrentLineWords = TEXT('\0'); //dont inc because we want to overwrite later lstrcpy(szCurrentLine, szCurrentLineWords); //append next word to string lstrcpy(szRemainedWords, pRemainedWords); pRemainedWords = szRemainedWords; } } } lstrcpy(pBBResource, szCurrentLine); pBBResource = &(pBBResource[lstrlen(szCurrentLine)+1]); iNumLines++; } HeapFree(GetProcessHeap(), 0, szRemainedWords); return iNumLines; } BOOL DrawWrapText( IN HDC hdc, IN TEXTMETRIC* lptm, IN int iLineSpace, IN int x, IN int y, IN RECT* lprc, IN WORD wfPlacement, IN int iLineCount, IN LPTSTR szLines) { UINT uiTxtAlign = 0; BOOL bRet = TRUE; SIZE sz; int Ly = 0; int Lx = 0; LPTSTR szText = szLines; int i = 0; if (g_bBiDi) { uiTxtAlign = GetTextAlign(hdc); SetTextAlign(hdc, uiTxtAlign|TA_RIGHT|TA_RTLREADING); } while (TRUE) { if(wfPlacement == CENTER) { //Get the dimensions of current string GetTextExtentPoint32(hdc, szText, lstrlen(szText), &sz); //x co-ord for TextOut if (g_bBiDi) Lx = lprc->right - (((lprc->right - lprc->left) - sz.cx)/2); else Lx = lprc->left + (((lprc->right - lprc->left) - sz.cx)/2); } else { //x co-ord for TextOut if (g_bBiDi) Lx = lprc->right - x; else Lx = lprc->left + x; } //calculate (y co-ord) for TextOut Ly = y + lptm->tmHeight * i + lptm->tmHeight * i * iLineSpace / 100; if (g_bBiDi) { bRet = ExtTextOut(hdc, Lx, Ly, ETO_RTLREADING, NULL, szText, lstrlen(szText), NULL); } else { bRet = TextOut(hdc, Lx, Ly, szText, lstrlen(szText)); } if (!bRet) break; if (++i >= iLineCount) break; szText = &(szText[lstrlen(szText)+1]); } if (g_bBiDi) { SetTextAlign(hdc, uiTxtAlign); } return bRet; } LPTSTR StringReverseChar( LPTSTR psz, TCHAR ch) { PTCHAR pch; pch = psz + lstrlen(psz); while (pch != psz && *pch != ch) { pch = CharPrev(psz, pch); } if (*pch != ch) { pch = NULL; } return pch; } VOID ImproveWrap( IN OUT LPTSTR szLines, IN OUT PINT piNumLine, IN LPTSTR szOrigText, IN INT cchOrigText ) /*++ Routine Description: Force to wrap the last 'wrappable' part of the last line, if the last line contains more than one 'wrappable' parts. Arguments: szLines - The result of WrapText, contains lines delimited by '\0' iNumLine - Number of line in szLines szOrigText - The original text that produces szLines, null-terminated cchOrigText - Number of characters in szOrigText Return Values: szLines - if the last line contains more than one 'wrappable' parts, szLines is modified. --*/ { #define NEAT_WRAPPING_RATIO 0.75 PTCHAR pLastLineStart; int cchLastLine; PTCHAR pLastWrapPartStart; int cchLastWrapPart; int iLineRemain; pLastLineStart = szLines; iLineRemain = *piNumLine; while (iLineRemain > 1) { pLastLineStart += lstrlen(pLastLineStart) + 1; iLineRemain--; } cchLastLine = lstrlen(pLastLineStart); pLastWrapPartStart = StringReverseChar(szOrigText, (TCHAR)'|'); if (pLastWrapPartStart != NULL) { pLastWrapPartStart = CharNext(pLastWrapPartStart); cchLastWrapPart = lstrlen(pLastWrapPartStart); if ((cchLastLine * NEAT_WRAPPING_RATIO) > (double)cchLastWrapPart) { LPTSTR szTmp = pLastLineStart + (cchLastLine - cchLastWrapPart); MoveMemory(szTmp + 1, szTmp, (cchLastWrapPart + 1) * sizeof(TCHAR)); szTmp[0] = (TCHAR)'\0'; (*piNumLine)++; } } }