// CreditStatic.cpp : implementation file // #include "stdafx.h" #include "CreditSt.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif // defined in MAIN.CPP extern HINSTANCE ghInstance; #define DISPLAY_TIMER_ID 150 // timer id ///////////////////////////////////////////////////////////////////////////// // CCreditStatic CCreditStatic::CCreditStatic() { m_Colors[0] = RGB(0,0,255); // Black m_Colors[1] = RGB(255,0,0); // Red m_Colors[2] = RGB(0,128,0); // John Deer Green m_Colors[3] = RGB(0,255,255); // Turquoise m_Colors[4] = RGB(255,255,255); // White m_TextHeights[0] = 36; m_TextHeights[1] = 34; m_TextHeights[2] = 34; m_TextHeights[3] = 30; m_nCurrentFontHeight = m_TextHeights[NORMAL_TEXT_HEIGHT]; m_Escapes[0] = '\t'; m_Escapes[1] = '\n'; m_Escapes[2] = '\r'; m_Escapes[3] = '^'; /* m_DisplaySpeed[0] = 75; m_DisplaySpeed[1] = 65; m_DisplaySpeed[2] = 15; */ m_CurrentSpeed = 15; //DISPLAY_FAST; m_ScrollAmount = -1; m_ArrIndex = NULL; m_nCounter = 31; m_nClip = 0; m_bFirstTurn = TRUE; m_Gradient = GRADIENT_RIGHT_DARK; n_MaxWidth = 0; TimerOn = 0; m_szWork = NULL; } CCreditStatic::~CCreditStatic() { } BEGIN_MESSAGE_MAP(CCreditStatic, CStatic) //{{AFX_MSG_MAP(CCreditStatic) ON_WM_ERASEBKGND() ON_WM_TIMER() ON_WM_DESTROY() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CCreditStatic message handlers BOOL CCreditStatic::StartScrolling() { if(m_pArrCredit->IsEmpty()) return FALSE; if (m_BmpMain) { DeleteObject(m_BmpMain); m_BmpMain = NULL; } ::GetClientRect(this->m_hWnd, &m_ScrollRect); TimerOn = (UINT)SetTimer(DISPLAY_TIMER_ID, m_CurrentSpeed, NULL); ASSERT(TimerOn != 0); m_ArrIndex = m_pArrCredit->GetHeadPosition(); // m_nCounter = 1; // m_nClip = 0; return TRUE; } void CCreditStatic::EndScrolling() { KillTimer(DISPLAY_TIMER_ID); TimerOn = 0; if (m_BmpMain) { DeleteObject(m_BmpMain); m_BmpMain = NULL; } } void CCreditStatic::SetCredits(LPCTSTR credits,TCHAR delimiter) { LPTSTR str,ptr1,ptr2; ASSERT(credits); if ((str = _tcsdup(credits)) == NULL) return; m_pArrCredit = new (CStringList); ASSERT (m_pArrCredit); m_pArrCredit->RemoveAll(); ptr1 = str; while((ptr2 = _tcschr(ptr1,delimiter)) != NULL) { *ptr2 = '\0'; m_pArrCredit->AddTail(ptr1); ptr1 = ptr2+1; } m_pArrCredit->AddTail(ptr1); free(str); m_ArrIndex = m_pArrCredit->GetHeadPosition(); // m_nCounter = 1; // m_nClip = 0; } BOOL CCreditStatic::OnEraseBkgnd(CDC* pDC) { return TRUE; // return CStatic::OnEraseBkgnd(pDC); } //************************************************************************ // OnTimer // // On each of the display timers, scroll the window 1 unit. Each 20 // units, fetch the next array element and load into work string. Call // Invalidate and UpdateWindow to invoke the OnPaint which will paint // the contents of the newly updated work string. //************************************************************************ void CCreditStatic::OnTimer(UINT nIDEvent) { BOOL bCheck = FALSE; if (m_nCounter++ % m_nCurrentFontHeight == 0) // every x timer events, show new line { m_nCounter=1; m_szWork = (LPCTSTR)m_pArrCredit->GetNext(m_ArrIndex); if(m_bFirstTurn) bCheck = TRUE; if (m_ArrIndex == NULL) { m_bFirstTurn = FALSE; m_ArrIndex = m_pArrCredit->GetHeadPosition(); } m_nClip = 0; } HDC hMainDC = this->GetDC()->m_hDC; RECT rc = m_ScrollRect; rc.left = ((rc.right-rc.left)-n_MaxWidth)/2; rc.right = rc.left + n_MaxWidth; HDC hDC = ::CreateCompatibleDC(hMainDC); // Don't try to scroll credits you don't have! if (m_szWork) MoveCredit(&hMainDC, rc, bCheck); else FillGradient(&hMainDC, m_ScrollRect); ::SelectObject(hDC, m_BmpMain); ::BitBlt(hMainDC, 0, 0, m_ScrollRect.right-m_ScrollRect.left, m_ScrollRect.bottom-m_ScrollRect.top, hDC, 0, 0, SRCCOPY); ::ReleaseDC(this->m_hWnd, hMainDC); ::DeleteDC(hDC); CStatic::OnTimer(nIDEvent); } void CCreditStatic::FillGradient(HDC *pDC, RECT& FillRect) { float fStep,fRStep,fGStep,fBStep; // How large is each band? WORD R = GetRValue(m_Colors[BACKGROUND_COLOR]); WORD G = GetGValue(m_Colors[BACKGROUND_COLOR]); WORD B = GetBValue(m_Colors[BACKGROUND_COLOR]); // Determine how large each band should be in order to cover the // client with 256 bands (one for every color intensity level) //if(m_Gradient % 2) //{ fRStep = (float)R / 255.0f; fGStep = (float)G / 255.0f; fBStep = (float)B / 255.0f; /* } else { fRStep = (float)(255-R) / 255.0f; fGStep = (float)(255-G) / 255.0f; fBStep = (float)(255-B) / 255.0f; } */ COLORREF OldCol = ::GetBkColor(*pDC); RECT rc; // Start filling bands fStep = (float)(m_ScrollRect.right-m_ScrollRect.left) / 256.0f; for (short iOnBand = (short)((256*FillRect.left)/(m_ScrollRect.right-m_ScrollRect.left)); (int)(iOnBand*fStep) < FillRect.right && iOnBand < 256; iOnBand++) { ::SetRect(&rc, (int)(iOnBand * fStep), FillRect.top, (int)((iOnBand+1) * fStep), FillRect.bottom+1); // If we want to enable gradient filling from any direction! /* switch(m_Gradient) { case GRADIENT_RIGHT_DARK: col = RGB((int)(R-iOnBand*fRStep),(int)(G-iOnBand*fGStep),(int)(B-iOnBand*fBStep)); break; case GRADIENT_RIGHT_LIGHT: col = RGB((int)(R+iOnBand*fRStep),(int)(G+iOnBand*fGStep),(int)(B+iOnBand*fBStep)); break; case GRADIENT_LEFT_DARK: col = RGB((int)(iOnBand*fRStep),(int)(iOnBand*fGStep),(int)(iOnBand*fBStep)); break; case GRADIENT_LEFT_LIGHT: col = RGB(255-(int)(iOnBand*fRStep),255-(int)(iOnBand*fGStep),255-(int)(iOnBand*fBStep)); break; default: return; } */ ::SetBkColor(*pDC, RGB((int)(R-iOnBand*fRStep),(int)(G-iOnBand*fGStep),(int)(B-iOnBand*fBStep))); ::ExtTextOut(*pDC, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL); } ::SetBkColor(*pDC, OldCol); } void CCreditStatic::MoveCredit(HDC* pDC, RECT& ClientRect, BOOL bCheck) { HDC hMemDC = ::CreateCompatibleDC(*pDC); HBITMAP *pOldMemDCBitmap = NULL; HFONT *pOldFont = NULL; RECT r1; if (m_BmpMain == NULL) { m_BmpMain = ::CreateCompatibleBitmap(*pDC, m_ScrollRect.right-m_ScrollRect.left, m_ScrollRect.bottom-m_ScrollRect.top ); pOldMemDCBitmap = (HBITMAP *)::SelectObject(hMemDC, m_BmpMain); FillGradient(&hMemDC, m_ScrollRect); } else pOldMemDCBitmap = (HBITMAP *)::SelectObject(hMemDC, m_BmpMain); if ((ClientRect.right-ClientRect.left) > 0) { ::ScrollDC(hMemDC, 0, m_ScrollAmount, &m_ScrollRect, &ClientRect, NULL, &r1); } else { r1 = m_ScrollRect; r1.top = r1.bottom-abs(m_ScrollAmount); } m_nClip = m_nClip + abs(m_ScrollAmount); //********************************************************************* // FONT SELECTIlON short rmcode = 1; if (lstrlen(m_szWork)) { BYTE bUnderline, bItalic; bUnderline = bItalic = FALSE; COLORREF nTmpColour = m_Colors[TOP_LEVEL_GROUP_COLOR]; TCHAR c = m_szWork[lstrlen(m_szWork)-1]; if(c == m_Escapes[TOP_LEVEL_GROUP]) { m_nCurrentFontHeight = m_TextHeights[TOP_LEVEL_GROUP_HEIGHT]; } else if(c == m_Escapes[GROUP_TITLE]) { m_nCurrentFontHeight = m_TextHeights[GROUP_TITLE_HEIGHT]; nTmpColour = m_Colors[GROUP_TITLE_COLOR]; } else if(c == m_Escapes[TOP_LEVEL_TITLE]) { m_nCurrentFontHeight = m_TextHeights[TOP_LEVEL_TITLE_HEIGHT]; nTmpColour = m_Colors[TOP_LEVEL_TITLE_COLOR]; } // If this were application critical, I'd make an array of fonts a member // and create all the fonts prior to starting the timer! HFONT pfntArial = ::CreateFont(m_nCurrentFontHeight, 0, 0, 0, FW_BOLD, bItalic, bUnderline, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, VARIABLE_PITCH | 0x04 | FF_DONTCARE, (LPCTSTR)"Arial"); ::SetTextColor(hMemDC, nTmpColour); if (pOldFont != NULL) ::SelectObject(hMemDC, pOldFont); pOldFont = (HFONT *)::SelectObject(hMemDC, pfntArial); } FillGradient(&hMemDC, r1); ::SetBkMode(hMemDC, TRANSPARENT); if(bCheck) { SIZE size; ::GetTextExtentPoint(hMemDC, (LPCTSTR)m_szWork,lstrlen(m_szWork)-rmcode, &size); if (size.cx > n_MaxWidth) { n_MaxWidth = (short)((size.cx > (m_ScrollRect.right-m_ScrollRect.left)) ? (m_ScrollRect.right-m_ScrollRect.left) : size.cx); ClientRect.left = ((m_ScrollRect.right-m_ScrollRect.left)-n_MaxWidth)/2; ClientRect.right = ClientRect.left + n_MaxWidth; } } RECT r = ClientRect; r.top = r.bottom-m_nClip; DrawText(hMemDC, (LPCTSTR)m_szWork,lstrlen(m_szWork)-rmcode,&r,DT_TOP|DT_CENTER|DT_NOPREFIX | DT_SINGLELINE); if (pOldFont != NULL) ::SelectObject(hMemDC, pOldFont); ::SelectObject(hMemDC, pOldMemDCBitmap); ::DeleteDC(hMemDC); } void CCreditStatic::OnDestroy() { CStatic::OnDestroy(); m_pArrCredit->RemoveAll(); if (m_pArrCredit) delete (m_pArrCredit); if(TimerOn) EndScrolling(); } /* In the event we ever want a few library routines! void CCreditStatic::SetCredits(UINT nID, TCHAR delimiter) { LPTSTR lpCredits = new (TCHAR[255]); ASSERT (lpCredits); ::LoadString(ghInstance, nID, lpCredits, 255); SetCredits((LPCTSTR)lpCredits, delimiter); if (lpCredits) delete[] (lpCredits); } void CCreditStatic::SetSpeed(UINT index, int speed) { ASSERT(index <= DISPLAY_FAST); if(speed) m_DisplaySpeed[index] = speed; m_CurrentSpeed = index; } void CCreditStatic::SetColor(UINT index, COLORREF col) { ASSERT(index <= NORMAL_TEXT_COLOR); m_Colors[index] = col; } void CCreditStatic::SetTextHeight(UINT index, int height) { ASSERT(index <= NORMAL_TEXT_HEIGHT); m_TextHeights[index] = height; } void CCreditStatic::SetEscape(UINT index, char escape) { ASSERT(index <= DISPLAY_BITMAP); m_Escapes[index] = escape; } void CCreditStatic::SetGradient(UINT value) { ASSERT(value <= GRADIENT_LEFT_LIGHT); m_Gradient = value; } void CCreditStatic::SetTransparent(BOOL bTransparent) { m_bTransparent = bTransparent; } */