1427 lines
37 KiB
C++
1427 lines
37 KiB
C++
// ==========================================================================
|
|
// Class Implementation : COXStaticText
|
|
// ==========================================================================
|
|
|
|
// Source file : OXStaticText.cpp
|
|
|
|
// Version: 9.3
|
|
|
|
// This software along with its related components, documentation and files ("The Libraries")
|
|
// is © 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
|
|
// governed by a software license agreement ("Agreement"). Copies of the Agreement are
|
|
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
|
|
// to obtain this file, or directly from our office. For a copy of the license governing
|
|
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
|
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "OXStaticText.h"
|
|
|
|
#include "UTBStrOp.h"
|
|
|
|
double __cdecl absolute(double a)
|
|
{
|
|
return ((a<0)?(-a):a)+0.5;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Data members -------------------------------------------------------------
|
|
// public:
|
|
|
|
// protected:
|
|
|
|
// int m_nHorzAlignment;
|
|
// --- Text horizontal alignment: left, center, right
|
|
|
|
// int m_nVertAlignment;
|
|
// --- Text vertical alignment: top, center, bottom
|
|
|
|
// BOOL m_bDottedEdge;
|
|
// --- Indicates whether the window edge is dotted.
|
|
|
|
// DWORD m_dwBkColor;
|
|
// --- Text background color.
|
|
|
|
// DWORD m_dwMinTimeOut;
|
|
// --- Minimum time out interval for text scrolling.
|
|
|
|
// DWORD m_dwOffset;
|
|
// --- Text 3D offset.
|
|
|
|
// DWORD m_dwScrollSpeed;
|
|
// --- Text scrolling speed (pixels/second).
|
|
|
|
// DWORD m_dwScrollTimeOut;
|
|
// --- Text scrolling time out period (ms).
|
|
|
|
// DWORD m_dwTextColor;
|
|
// --- Text color.
|
|
|
|
// double m_dXDelta;
|
|
// --- Exact text scrolling x-increment.
|
|
|
|
// double m_dXExactDisplacement;
|
|
// --- Exact text scrolling x-displacement.
|
|
|
|
// double m_dYDelta;
|
|
// --- Exact text scrolling y-increment.
|
|
|
|
// double m_dYExactDisplacement;
|
|
// --- Exact text scrolling y-displacement.
|
|
|
|
// LOGFONT m_LogFont;
|
|
// --- Structure defines the attributes of a font.
|
|
|
|
// int m_nEllipseMode;
|
|
// --- Ellipses replacing mode.
|
|
|
|
// int m_nGraphicsMode;
|
|
// --- Current graphics mode.
|
|
|
|
// int m_nScrollAmount;
|
|
// --- Text scrolling amount.
|
|
|
|
// int m_nScrollDirection;
|
|
// --- Text scrolling direction (degrees).
|
|
|
|
// int m_nXCastDisplacement;
|
|
// --- Text scrolling cast x-displacement.
|
|
|
|
// int m_nXDisplacement;
|
|
// --- Text scrolling x-displacement.
|
|
|
|
// int m_nYCastDisplacement;
|
|
// --- Text scrolling cast y-displacement.
|
|
|
|
// int m_nYDisplacement;
|
|
// --- Text scrolling y-displacement.
|
|
|
|
// CEvent* m_pEventLoop;
|
|
// --- When pointed event is signaled, text scrolling thread terminates.
|
|
|
|
// CCriticalSection* m_pCritSecRedrawWait;
|
|
// --- Pointed critical section is locked during window redrawing;
|
|
|
|
// CFont* m_pObjFont;
|
|
// --- Pointer to the font object.
|
|
|
|
// CSingleLock* m_pRedrawThreadLock;
|
|
// --- This object locks window redrawing in the special redraw thread.
|
|
|
|
// CWinThread* m_pScrollingThread;
|
|
// --- Points to CWinThread object that represents text scrolling thread.
|
|
|
|
// CString m_sText;
|
|
// --- Text string.
|
|
|
|
// CString m_sTextNarrow;
|
|
// --- Narrow text string (with ellipses so that the result fits in the specified rectangle).
|
|
|
|
// private:
|
|
|
|
UINT COXStaticText::m_nPrepareBitmap=
|
|
RegisterWindowMessage(_T("_OXPREPARE_BITMAP_"));
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Member functions ---------------------------------------------------------
|
|
// public:
|
|
|
|
COXStaticText::COXStaticText(DWORD dwOffset, int nGraphicsMode,
|
|
int nHorzAlignment, int nVertAlignment) : m_BMP(NULL)
|
|
{
|
|
m_bAllowRefresh = FALSE;
|
|
m_dwCurrentTickDelta = 0;
|
|
m_dwLastTickDelta = 0;
|
|
|
|
m_nHorzAlignment = nHorzAlignment;
|
|
m_nVertAlignment = nVertAlignment;
|
|
|
|
m_bDottedEdge = FALSE;
|
|
|
|
m_bEmbossText = FALSE;
|
|
m_bEmbossRaised = FALSE;
|
|
m_clrEmbossHighLight = ::GetSysColor(COLOR_BTNHIGHLIGHT);
|
|
m_clrEmbossShadow = ::GetSysColor(COLOR_BTNSHADOW);
|
|
|
|
m_dwBkColor = ::GetSysColor(COLOR_WINDOW);
|
|
m_dwMinTimeOut = 10;
|
|
m_dwOffset = dwOffset;
|
|
m_dwScrollSpeed = m_dwScrollTimeOut = 0;
|
|
m_dwTextColor = ::GetSysColor(COLOR_WINDOWTEXT);
|
|
|
|
m_dXDelta = m_dYDelta = 0.0;
|
|
|
|
::GetObject(::GetStockObject(ANSI_VAR_FONT), sizeof(m_LogFont), &m_LogFont);
|
|
|
|
m_nEllipseMode = OX_NO_ELLIPSES;
|
|
m_nGraphicsMode = nGraphicsMode;
|
|
m_nScrollAmount = m_nScrollDirection = 0;
|
|
m_nXDisplacement = m_nYDisplacement = m_nXCastDisplacement = m_nYCastDisplacement = 0;
|
|
|
|
m_pEventLoop = new CEvent(FALSE, TRUE);
|
|
m_pCritSecRedrawWait = new CCriticalSection();
|
|
|
|
m_pObjFont = new CFont;
|
|
m_pObjFont->CreateFontIndirect(&m_LogFont);
|
|
|
|
m_pScrollingThread = NULL;
|
|
|
|
m_sText = m_sTextNarrow = _T("");
|
|
|
|
m_szGapSize=CSize(0,0);
|
|
|
|
m_rectViewMargins=CRect(2,0,2,0);
|
|
}
|
|
|
|
BOOL COXStaticText::Create(LPCTSTR lpszText, DWORD dwStyle, const RECT& rect,
|
|
CWnd* pParentWnd, UINT nID /* = 0xffff */)
|
|
{
|
|
// Look for special CStatic control styles and trace if any.
|
|
#ifdef _DEBUG
|
|
if ((dwStyle & ~(WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_BORDER)) != 0)
|
|
TRACE0("in COXStaticText::Create : dwStyle contains more styles than permitted. They will be ignored\n");
|
|
#endif
|
|
|
|
dwStyle&=WS_CHILD|WS_VISIBLE|WS_DISABLED|WS_BORDER;
|
|
return CStatic::Create(lpszText, dwStyle, rect, pParentWnd, nID);
|
|
}
|
|
|
|
COXStaticText::~COXStaticText()
|
|
{
|
|
m_pObjFont->DeleteObject();
|
|
delete m_pObjFont;
|
|
|
|
delete m_pCritSecRedrawWait;
|
|
delete m_pEventLoop;
|
|
|
|
delete m_BMP;
|
|
}
|
|
|
|
BOOL COXStaticText::SetHorzAlignment(int nAlignment, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
if(nAlignment!=OX_ALIGNHORZ_LEFT && nAlignment!=OX_ALIGNHORZ_CENTER &&
|
|
nAlignment!=OX_ALIGNHORZ_RIGHT)
|
|
{
|
|
return FALSE;
|
|
}
|
|
m_nHorzAlignment = nAlignment;
|
|
return RestoreTextPos(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetVertAlignment(int nAlignment, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
if(nAlignment!=OX_ALIGNVERT_TOP && nAlignment!=OX_ALIGNVERT_CENTER &&
|
|
nAlignment!=OX_ALIGNVERT_BOTTOM)
|
|
{
|
|
return FALSE;
|
|
}
|
|
m_nVertAlignment = nAlignment;
|
|
return RestoreTextPos(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetBkColor(COLORREF dwBkColor, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_dwBkColor = dwBkColor;
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetTextColor(COLORREF dwTextColor, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_dwTextColor = dwTextColor;
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetEmboss(BOOL bEmboss /* = TRUE */, BOOL bRaised /* = FALSE */, BOOL bPrepareNow /* = FALSE */,
|
|
COLORREF clrHLight /* = ::GetSysColor(COLOR_BTNHIGHLIGHT) */,
|
|
COLORREF clrShadow /* = ::GetSysColor(COLOR_BTNSHADOW) */)
|
|
{
|
|
m_bEmbossText = bEmboss;
|
|
m_bEmbossRaised = bRaised;
|
|
|
|
m_clrEmbossHighLight = clrHLight;
|
|
m_clrEmbossShadow = clrShadow;
|
|
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetWindowText(LPCTSTR psText, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_sText = m_sTextNarrow = psText;
|
|
m_bAllowRefresh = FALSE;
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetGraphicsMode(int nGraphicsMode, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_nGraphicsMode = nGraphicsMode;
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::SetEllipseMode(int nEllipseMode, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
if ( GetEllipseMode() == nEllipseMode )
|
|
m_nEllipseMode = OX_NO_ELLIPSES;
|
|
else
|
|
m_nEllipseMode = nEllipseMode;
|
|
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BOOL COXStaticText::Set3Doffset(DWORD dwOffset, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if ( dwOffset <= OX_MAX_3DOFFSET )
|
|
{
|
|
m_dwOffset = dwOffset;
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetFontAttr(int nAttr, BOOL bSet /* = TRUE */, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
switch ( nAttr )
|
|
{
|
|
case OX_BOLD_FONT:
|
|
m_LogFont.lfWeight = bSet ? FW_BOLD : FW_NORMAL;
|
|
break;
|
|
case OX_ITALIC_FONT:
|
|
m_LogFont.lfItalic = (BYTE)bSet;
|
|
break;
|
|
case OX_UNDERLINED_FONT:
|
|
m_LogFont.lfUnderline = (BYTE)bSet;
|
|
break;
|
|
case OX_STRIKED_OUT_FONT:
|
|
m_LogFont.lfStrikeOut = (BYTE)bSet;
|
|
break;
|
|
}
|
|
|
|
BOOL bSuccess = RebuildFont();
|
|
if (bSuccess)
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::IsBold() const
|
|
{
|
|
if ( m_LogFont.lfWeight == FW_BOLD )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL COXStaticText::SetStringAngle(int nAngle, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_LogFont.lfEscapement = nAngle;
|
|
|
|
BOOL bSuccess = RebuildFont();
|
|
if ( bSuccess )
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetCharAngle(int nAngle, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_LogFont.lfOrientation = nAngle;
|
|
|
|
BOOL bSuccess = RebuildFont();
|
|
if ( bSuccess )
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetCharSet(int nCharSet, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_LogFont.lfCharSet = (BYTE)nCharSet;
|
|
|
|
BOOL bSuccess = RebuildFont();
|
|
if ( bSuccess )
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetFontHeight(int nHeight, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_LogFont.lfHeight = nHeight;
|
|
|
|
BOOL bSuccess = RebuildFont();
|
|
if ( bSuccess )
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetFontWidth(int nWidth, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_LogFont.lfWidth = nWidth;
|
|
|
|
BOOL bSuccess = RebuildFont();
|
|
if ( bSuccess )
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetFontName(LPCTSTR sName, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if ( _tcslen(sName) <= LF_FACESIZE )
|
|
{
|
|
UTBStr::tcscpy(m_LogFont.lfFaceName, LF_FACESIZE, sName);
|
|
|
|
bSuccess = RebuildFont();
|
|
if ( bSuccess )
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
// returns TRUE if succeed and sets plf to the LOGINFO of the font used to draw text,
|
|
// otherwise FALSE and plf is undefined
|
|
BOOL COXStaticText::GetLogFont(LOGFONT* plf) const
|
|
{
|
|
if (m_pObjFont==NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
return m_pObjFont->GetObject(sizeof(*plf),plf);
|
|
}
|
|
|
|
// returns TRUE if succeed and creates font used to draw text
|
|
// from plf, otherwise FALSE
|
|
BOOL COXStaticText::SetLogFont(LOGFONT* plf, BOOL bPrepareNow/* = FALSE*/)
|
|
{
|
|
CFont font;
|
|
BOOL bSuccess=font.CreateFontIndirect(plf);
|
|
if(bSuccess)
|
|
{
|
|
bSuccess = font.GetObject(sizeof(m_LogFont),&m_LogFont);
|
|
if(bSuccess)
|
|
{
|
|
bSuccess = RebuildFont();
|
|
if(bSuccess)
|
|
{
|
|
bSuccess = PrepareBitmap(bPrepareNow);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL COXStaticText::SetPlainBorder(BOOL bSet /* = TRUE */)
|
|
{
|
|
if (bSet)
|
|
{
|
|
m_bDottedEdge = FALSE;
|
|
// This odd line is to force the NC area to be invalidated
|
|
ModifyStyleEx(0, WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE, 0);
|
|
|
|
ModifyStyle(0, WS_BORDER, 0);
|
|
ModifyStyleEx(WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE, 0, SWP_FRAMECHANGED);
|
|
}
|
|
else
|
|
ModifyStyle(WS_BORDER, 0, SWP_FRAMECHANGED);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXStaticText::SetStaticEdge(BOOL bSet /* = TRUE */)
|
|
{
|
|
if (bSet)
|
|
{
|
|
m_bDottedEdge = FALSE;
|
|
ModifyStyle(0, WS_BORDER, 0);
|
|
ModifyStyleEx(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE, WS_EX_STATICEDGE, SWP_FRAMECHANGED);
|
|
}
|
|
else
|
|
ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_FRAMECHANGED);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXStaticText::SetClientEdge(BOOL bSet /* = TRUE */)
|
|
{
|
|
if (bSet)
|
|
{
|
|
m_bDottedEdge = FALSE;
|
|
ModifyStyle(0, WS_BORDER, 0);
|
|
ModifyStyleEx(WS_EX_STATICEDGE | WS_EX_WINDOWEDGE, WS_EX_CLIENTEDGE, SWP_FRAMECHANGED);
|
|
}
|
|
else
|
|
ModifyStyleEx(WS_EX_CLIENTEDGE, 0, SWP_FRAMECHANGED);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXStaticText::SetRaisedEdge(BOOL bSet /* = TRUE */)
|
|
{
|
|
if (bSet)
|
|
{
|
|
m_bDottedEdge = FALSE;
|
|
ModifyStyle(0, WS_BORDER, 0);
|
|
ModifyStyleEx(WS_EX_STATICEDGE | WS_EX_CLIENTEDGE, WS_EX_WINDOWEDGE, SWP_FRAMECHANGED);
|
|
}
|
|
else
|
|
ModifyStyleEx(WS_EX_WINDOWEDGE, 0, SWP_FRAMECHANGED);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXStaticText::SetDottedEdge(BOOL bSet /* = TRUE */)
|
|
{
|
|
m_bDottedEdge = bSet;
|
|
if (bSet)
|
|
{
|
|
// This odd line is to force the NC area to be invalidated
|
|
ModifyStyleEx(0, WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE, 0);
|
|
|
|
ModifyStyle(0, WS_BORDER, 0);
|
|
ModifyStyleEx(WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE, 0, SWP_FRAMECHANGED);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void COXStaticText::SetScrollDirection(int nDirection, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
CSingleLock RedrawLock(m_pCritSecRedrawWait);
|
|
RedrawLock.Lock();
|
|
|
|
// Correct direction angle to keep it in [0 - 360] interval.
|
|
nDirection %= 360;
|
|
if ( nDirection < 0 )
|
|
nDirection += 360;
|
|
|
|
m_nScrollDirection = nDirection;
|
|
RestoreTextPos(bPrepareNow);
|
|
ScrollAmountRecalc();
|
|
|
|
RedrawLock.Unlock();
|
|
}
|
|
|
|
void COXStaticText::SetScrollSpeed(DWORD dwScrollSpeed)
|
|
{
|
|
CSingleLock RedrawLock(m_pCritSecRedrawWait);
|
|
RedrawLock.Lock();
|
|
|
|
DWORD dwTimeOut, dwAmount;
|
|
SpeedCalc(dwScrollSpeed, &dwTimeOut, &dwAmount);
|
|
|
|
m_dwScrollSpeed = dwScrollSpeed;
|
|
m_dwScrollTimeOut = dwTimeOut;
|
|
m_nScrollAmount = dwAmount;
|
|
ScrollAmountRecalc();
|
|
|
|
RedrawLock.Unlock();
|
|
}
|
|
|
|
void COXStaticText::StartScrolling(BOOL bStart)
|
|
{
|
|
if(GetSafeHwnd()==NULL)
|
|
return;
|
|
|
|
if ( IsScrollingStarted() )
|
|
{
|
|
m_pEventLoop->SetEvent();
|
|
|
|
DWORD dwWaitResult;
|
|
BOOL bEnd = FALSE;
|
|
BOOL bPostQuit = FALSE;
|
|
|
|
while (!bEnd)
|
|
{
|
|
dwWaitResult = MsgWaitForMultipleObjects(1, &m_pScrollingThread->m_hThread, FALSE, INFINITE, QS_ALLINPUT);
|
|
|
|
if (dwWaitResult == (WAIT_OBJECT_0 + 1))
|
|
{
|
|
MSG msg;
|
|
// making sure there is a msg in the queue
|
|
// we don't want PumpMessage() to hang
|
|
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
|
|
bPostQuit = (!AfxGetThread()->PumpMessage()) || bPostQuit;
|
|
}
|
|
else
|
|
{
|
|
//if (dwWaitResult != WAIT_OBJECT_0)
|
|
// TerminateThread(h_thread, 0);
|
|
bEnd = TRUE;
|
|
}
|
|
}
|
|
if (bPostQuit)
|
|
{
|
|
AfxPostQuitMessage(0);
|
|
Sleep(200); // Give the terminating thread the time to terminate
|
|
}
|
|
|
|
m_pEventLoop->ResetEvent();
|
|
delete m_pScrollingThread;
|
|
m_pScrollingThread = NULL;
|
|
}
|
|
|
|
if ( bStart )
|
|
{
|
|
m_pScrollingThread = AfxBeginThread((AFX_THREADPROC)TextScrollingThreadFunction, this);
|
|
m_pScrollingThread->m_bAutoDelete = FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL COXStaticText::IsScrollingStarted() const
|
|
{
|
|
if ( m_pScrollingThread &&
|
|
::WaitForSingleObject(m_pScrollingThread->m_hThread, 0) == WAIT_TIMEOUT )
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
void COXStaticText::SetMinTimeOut(DWORD dwMinTimeOut)
|
|
{
|
|
if ( dwMinTimeOut != m_dwMinTimeOut && dwMinTimeOut >= 1 && dwMinTimeOut <= 500 )
|
|
{
|
|
DWORD dwScrollSpeed = GetScrollSpeed();
|
|
m_dwMinTimeOut = dwMinTimeOut;
|
|
SetScrollSpeed(dwScrollSpeed);
|
|
}
|
|
}
|
|
|
|
void COXStaticText::SetGapSize(CSize& szGapSize, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_szGapSize = szGapSize;
|
|
|
|
PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
void COXStaticText::SetViewMargins(CRect& rectViewMargins, BOOL bPrepareNow /* = FALSE */)
|
|
{
|
|
m_rectViewMargins = rectViewMargins;
|
|
|
|
PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
|
|
BOOL COXStaticText::RestoreTextPos(BOOL bPrepareNow /* = TRUE */)
|
|
{
|
|
CRect textRect;
|
|
GetClientRect(&textRect);
|
|
|
|
|
|
GetInitialDisplacement(textRect);
|
|
|
|
return PrepareBitmap(bPrepareNow);
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(COXStaticText, CStatic)
|
|
//{{AFX_MSG_MAP(COXStaticText)
|
|
ON_WM_PAINT()
|
|
ON_WM_DESTROY()
|
|
ON_WM_ERASEBKGND()
|
|
ON_WM_NCPAINT()
|
|
ON_WM_SIZE()
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE(WM_DISPLAYCHANGE, OnDisplayChange)
|
|
ON_REGISTERED_MESSAGE(m_nPrepareBitmap, OnPrepareBitmap)
|
|
END_MESSAGE_MAP()
|
|
|
|
// protected:
|
|
void COXStaticText::OnNcPaint()
|
|
{
|
|
if (!m_bDottedEdge)
|
|
{
|
|
Default();
|
|
return;
|
|
}
|
|
|
|
// Prepare for drawing the non-client area with a dotted border
|
|
CWindowDC dc(this);
|
|
CRect rect;
|
|
GetWindowRect(&rect);
|
|
|
|
rect.OffsetRect(-rect.left, -rect.top);
|
|
|
|
CRect Temp;
|
|
GetClientRect(&Temp);
|
|
|
|
CPen DottedPen(PS_DOT, 1, RGB(0, 0, 0));
|
|
CBrush HollowBrush;
|
|
HollowBrush.CreateStockObject(HOLLOW_BRUSH);
|
|
|
|
CPen* pOldPen = dc.SelectObject(&DottedPen);
|
|
CBrush* pOldBrush = dc.SelectObject(&HollowBrush);
|
|
dc.Rectangle(rect);
|
|
|
|
if (pOldBrush != NULL)
|
|
dc.SelectObject(pOldBrush);
|
|
|
|
if (pOldPen != NULL)
|
|
dc.SelectObject(pOldPen);
|
|
}
|
|
|
|
void COXStaticText::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CStatic::OnSize(nType,cx,cy);
|
|
if(IsScrollingStarted())
|
|
StartScrolling(TRUE);
|
|
PrepareBitmap(TRUE);
|
|
}
|
|
|
|
UINT COXStaticText::TextScrollingThreadFunction(LPVOID pParam)
|
|
// --- In : pParam : Pointer to this COXStaticText object. It makes possible to
|
|
// work with non-static class members in this static function.
|
|
// --- Out :
|
|
// --- Returns : Exit code = 0.
|
|
// --- Effect : Controlling function for text scrolling worker thread.
|
|
{
|
|
COXStaticText* pStaText = (COXStaticText*)pParam;
|
|
CSingleLock LoopLock(pStaText->m_pEventLoop), RedrawLock(pStaText->m_pCritSecRedrawWait);
|
|
BOOL bRedraw;
|
|
|
|
pStaText->PrepareBitmap(TRUE);
|
|
|
|
CRect textRect;
|
|
pStaText->GetClientRect(&textRect);
|
|
///
|
|
textRect+=pStaText->m_szGapSize;
|
|
///
|
|
|
|
while (TRUE)
|
|
{
|
|
if(LoopLock.Lock(pStaText->m_dwScrollTimeOut))
|
|
return 0;
|
|
|
|
bRedraw = FALSE;
|
|
|
|
RedrawLock.Lock();
|
|
|
|
double nXDisplacement = pStaText->m_nXDisplacement,
|
|
nYDisplacement = pStaText->m_nYDisplacement;
|
|
|
|
pStaText->m_nXDisplacement = (pStaText->m_dXDelta + pStaText->m_nXDisplacement);
|
|
pStaText->m_nYDisplacement = (pStaText->m_dYDelta + pStaText->m_nYDisplacement);
|
|
|
|
if ( pStaText->m_nXDisplacement != nXDisplacement ||
|
|
pStaText->m_nYDisplacement != nYDisplacement )
|
|
{
|
|
if(pStaText->m_nXDisplacement-pStaText->m_szTextSize.cx/2>=textRect.right ||
|
|
pStaText->m_nXDisplacement+pStaText->m_szTextSize.cx/2<0 ||
|
|
pStaText->m_nYDisplacement-pStaText->m_szTextSize.cy/2>=textRect.bottom ||
|
|
pStaText->m_nYDisplacement+pStaText->m_szTextSize.cy/2<0)
|
|
{
|
|
pStaText->m_nXDisplacement += pStaText->m_nXCastDisplacement;
|
|
pStaText->m_nYDisplacement += pStaText->m_nYCastDisplacement;
|
|
|
|
if(pStaText->m_nXDisplacement-pStaText->m_szTextSize.cx/2>=textRect.right ||
|
|
pStaText->m_nXDisplacement+pStaText->m_szTextSize.cx/2<0 ||
|
|
pStaText->m_nYDisplacement-pStaText->m_szTextSize.cy/2>=textRect.bottom ||
|
|
pStaText->m_nYDisplacement+pStaText->m_szTextSize.cy/2<0)
|
|
{
|
|
pStaText->m_nXDisplacement -= pStaText->m_nXCastDisplacement;
|
|
pStaText->m_nYDisplacement -= pStaText->m_nYCastDisplacement;
|
|
}
|
|
}
|
|
|
|
bRedraw = TRUE;
|
|
}
|
|
|
|
|
|
RedrawLock.Unlock();
|
|
|
|
if (bRedraw)
|
|
pStaText->RedrawWindow();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void COXStaticText::EmbossText(CDC* pMemDC, RECT BmpRect)
|
|
{
|
|
const DWORD PSDPxax = 0x00B8074A;
|
|
|
|
COLORREF clrShadow = m_clrEmbossShadow;
|
|
COLORREF clrHighlight = m_clrEmbossHighLight;
|
|
if(!m_bEmbossRaised)
|
|
{
|
|
// Swap the highlight and shadow color
|
|
clrShadow = m_clrEmbossHighLight;
|
|
clrHighlight = m_clrEmbossShadow;
|
|
}
|
|
|
|
// We create two monochrome bitmaps. One of them will contain the
|
|
// highlighted edge and the other will contain the shadow. These
|
|
// bitmaps are then used to paint the highlight and shadow on the
|
|
// background image.
|
|
CDC* pDC = GetDC();
|
|
|
|
// Create compatible DCs
|
|
CDC MonoDC;
|
|
MonoDC.CreateCompatibleDC(pDC);
|
|
CDC* pMonoDC = &MonoDC;
|
|
|
|
int BmpWidth = BmpRect.right - BmpRect.left;
|
|
int BmpHeight = BmpRect.bottom - BmpRect.top;
|
|
// Create the monochrome and compatible color bitmaps
|
|
CBitmap bmShadow;
|
|
bmShadow.CreateBitmap(BmpWidth, BmpHeight, 1, 1, NULL);
|
|
CBitmap bmHighlight;
|
|
bmHighlight.CreateBitmap(BmpWidth, BmpHeight, 1, 1, NULL);
|
|
|
|
// Set background color of bitmap for mono conversion
|
|
// We assume that the pixel in the top left corner has the background color
|
|
COLORREF oldBkColor=CLR_NONE;
|
|
if(m_dwBkColor!=CLR_NONE)
|
|
oldBkColor = pMemDC->SetBkColor(pMemDC->GetNearestColor(m_dwBkColor));
|
|
|
|
// Create the highlight bitmap.
|
|
CBitmap* pbmOldHighlight = pMonoDC->SelectObject(&bmHighlight);
|
|
pMonoDC->PatBlt(0, 0, BmpWidth, BmpHeight, WHITENESS );
|
|
pMonoDC->BitBlt(0, 0, BmpWidth - 1, BmpHeight - 1, pMemDC, 1, 1, SRCCOPY );
|
|
pMonoDC->BitBlt(0, 0, BmpWidth, BmpHeight, pMemDC, BmpRect.left, BmpRect.top, MERGEPAINT );
|
|
pbmOldHighlight = pMonoDC->SelectObject(pbmOldHighlight);
|
|
|
|
// create the shadow bitmap
|
|
CBitmap* pbmOldShadow = pMonoDC->SelectObject(&bmShadow);
|
|
pMonoDC->PatBlt(0, 0, BmpWidth, BmpHeight, WHITENESS );
|
|
pMonoDC->BitBlt(0, 0, BmpWidth - 1, BmpHeight - 1, pMemDC, 1, 1, SRCCOPY );
|
|
pMonoDC->BitBlt(0, 0, BmpWidth, BmpHeight, pMemDC, BmpRect.left, BmpRect.top, MERGEPAINT );
|
|
pbmOldShadow = pMonoDC->SelectObject(pbmOldShadow);
|
|
|
|
// Now let's start working on the final image
|
|
// Set the background and foreground color for the raster operations
|
|
pMemDC->SetBkColor(pMemDC->GetNearestColor(RGB(255,255,255)));
|
|
pMemDC->SetTextColor(pMemDC->GetNearestColor(RGB(0,0,0)));
|
|
|
|
// blt the highlight edge
|
|
CBrush brHighPat(pMemDC->GetNearestColor(clrHighlight));
|
|
CBrush* pOldbrHighPat = pMemDC->SelectObject(&brHighPat);
|
|
pbmOldHighlight = pMonoDC->SelectObject(pbmOldHighlight);
|
|
pMemDC->BitBlt(BmpRect.left, BmpRect.top, BmpWidth, BmpHeight, pMonoDC, 0, 0, PSDPxax);
|
|
pMemDC->SelectObject(pOldbrHighPat);
|
|
pMonoDC->SelectObject(pbmOldHighlight);
|
|
|
|
// blt the shadow edge
|
|
CBrush brShwPat(clrShadow);
|
|
CBrush* pOldbrShwPat = pMemDC->SelectObject(&brShwPat);
|
|
pbmOldShadow = pMonoDC->SelectObject(pbmOldShadow);
|
|
pMemDC->BitBlt(BmpRect.left, BmpRect.top, BmpWidth, BmpHeight, pMonoDC, 0, 0, PSDPxax);
|
|
pMemDC->SelectObject(pOldbrShwPat);
|
|
pMonoDC->SelectObject(pbmOldShadow);
|
|
|
|
bmShadow.DeleteObject();
|
|
bmHighlight.DeleteObject();
|
|
|
|
ReleaseDC(pDC);
|
|
|
|
pMemDC->SetBkColor(oldBkColor);
|
|
}
|
|
|
|
void COXStaticText::TextOutput(CDC* pMemDC, RECT rect)
|
|
// --- In : pMemDC : Pointer to compatible memory device context to text output.
|
|
// rect : Text output rectangle.
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : Performs text output to the compatible memory device context.
|
|
{
|
|
rect.left+=m_rectViewMargins.left;
|
|
rect.top+=m_rectViewMargins.top;
|
|
rect.right-=m_rectViewMargins.right;
|
|
rect.bottom-=m_rectViewMargins.bottom;
|
|
|
|
TEXTMETRIC tm;
|
|
pMemDC->GetTextMetrics(&tm);
|
|
double alpha = ((GetGraphicsMode()==GM_ADVANCED) ?
|
|
GetCharAngle() : GetStringAngle())/10;
|
|
alpha = alpha * 3.1415926/180.0;
|
|
double alphaAdvanced = GetStringAngle()/10;
|
|
alphaAdvanced = alphaAdvanced * 3.1415926/180.0;
|
|
|
|
CSize sizeCorr(0,0);
|
|
sizeCorr.cx = (tm.tmAscent - tm.tmDescent)/2;
|
|
sizeCorr.cy = (tm.tmAscent - tm.tmDescent)/2;
|
|
sizeCorr.cx = (int)(((double)sizeCorr.cx)*sin(alpha)+(sin(alpha)>0 ? -0.5 : 0.5));
|
|
sizeCorr.cy = (int)(((double)sizeCorr.cy)*cos(alpha)+(cos(alpha)>0 ? -0.5 : 0.5));
|
|
if(GetGraphicsMode()==GM_ADVANCED)
|
|
{
|
|
}
|
|
|
|
pMemDC->SetTextAlign(TA_CENTER | TA_BASELINE | TA_NOUPDATECP);
|
|
pMemDC->SetTextColor(pMemDC->GetNearestColor(RGB(GetRValue(m_dwTextColor)/2, GetGValue(m_dwTextColor)/2, GetBValue(m_dwTextColor)/2)));
|
|
for ( DWORD dwCount = 0; dwCount < m_dwOffset; dwCount++ )
|
|
{
|
|
pMemDC->TextOut( (rect.left+rect.right)/2+sizeCorr.cx,
|
|
(rect.top+rect.bottom)/2+sizeCorr.cy, m_sTextNarrow);
|
|
CRect rectOutput((rect.left+rect.right)/2+sizeCorr.cx,
|
|
(rect.top+rect.bottom)/2+sizeCorr.cy,
|
|
(rect.left+rect.right)/2+sizeCorr.cx+rect.right-rect.left,
|
|
(rect.top+rect.bottom)/2+sizeCorr.cy+rect.bottom-rect.top);
|
|
ScreenToClient(rectOutput);
|
|
pMemDC->DrawText(m_sTextNarrow, &rectOutput,DT_SINGLELINE);
|
|
OffsetRect( &rect, 1,1);
|
|
}
|
|
|
|
pMemDC->SetTextColor(pMemDC->GetNearestColor(m_dwTextColor));
|
|
pMemDC->TextOut( (rect.left+rect.right)/2+sizeCorr.cx,
|
|
(rect.top+rect.bottom)/2+sizeCorr.cy, m_sTextNarrow);
|
|
if (m_bEmbossText)
|
|
EmbossText(pMemDC, rect);
|
|
}
|
|
|
|
void COXStaticText::EllipsesReplace(CDC* pMemDC, LPRECT lpRect)
|
|
// --- In : pMemDC : Pointer to compatible memory device context to text output.
|
|
// lpRect : Pointer to the text output rectangle.
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : If it's necessary, replaces text with ellipses so that
|
|
// the result fits in the specified rectangle
|
|
{
|
|
BOOL bContinue = TRUE;
|
|
int nRemoved = 0, nRem1 = 0, nRem2 = 0;
|
|
CString sEllipses = _T("...");
|
|
CSize textSize;
|
|
|
|
m_sTextNarrow = m_sText;
|
|
|
|
int nLimit=lpRect->right-(int)(lpRect->right*1/4*
|
|
sin((double)(GetStringAngle()/10)*OX_PI/180.0));
|
|
|
|
while ( bContinue && m_sText.GetLength() > nRemoved &&
|
|
::GetTextExtentPoint32(pMemDC->m_hDC, (LPCTSTR)m_sTextNarrow,
|
|
m_sTextNarrow.GetLength(), &textSize) )
|
|
{
|
|
if(textSize.cx>=nLimit)
|
|
{
|
|
nRemoved++;
|
|
|
|
switch(m_nEllipseMode)
|
|
{
|
|
case OX_BEGIN_ELLIPSES:
|
|
m_sTextNarrow = sEllipses + m_sText.Right(m_sText.GetLength() -
|
|
nRemoved);
|
|
break;
|
|
case OX_MIDDLE_ELLIPSES:
|
|
nRem1 = m_sText.GetLength() - nRemoved;
|
|
if ( nRem1 % 2 )
|
|
{
|
|
nRem1 /= 2;
|
|
nRem2 = nRem1 + 1;
|
|
}
|
|
else
|
|
nRem2 = nRem1 /= 2;
|
|
m_sTextNarrow = m_sText.Left(nRem1) + sEllipses +
|
|
m_sText.Right(nRem2);
|
|
break;
|
|
case OX_END_ELLIPSES:
|
|
m_sTextNarrow = m_sText.Left(m_sText.GetLength() - nRemoved) +
|
|
sEllipses;
|
|
break;
|
|
default:
|
|
bContinue = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
bContinue = FALSE;
|
|
}
|
|
}
|
|
|
|
void COXStaticText::ScrollAmountRecalc()
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : Calculates the text scrolling x- and y- offsets.
|
|
{
|
|
double dRadDirection = (double)m_nScrollDirection * OX_PI / 180.0;
|
|
|
|
m_dXDelta = (double)m_nScrollAmount * cos(dRadDirection);
|
|
m_dYDelta = -(double)m_nScrollAmount * sin(dRadDirection);
|
|
|
|
RECT textRect;
|
|
GetClientRect(&textRect);
|
|
|
|
textRect.right = __max( textRect.right, m_szTextSize.cx)+m_szGapSize.cx;
|
|
textRect.bottom = __max( textRect.bottom, m_szTextSize.cy)+m_szGapSize.cy;
|
|
|
|
double angle = atan( ((double)textRect.bottom)/((double)textRect.right));
|
|
angle = (angle*180.0)/OX_PI;
|
|
|
|
if ( m_nScrollDirection <= angle )
|
|
{
|
|
m_nXCastDisplacement = -textRect.right;
|
|
m_nYCastDisplacement = ((double)textRect.right * tan(dRadDirection));
|
|
}
|
|
else if ( m_nScrollDirection > angle && m_nScrollDirection <= 90 )
|
|
{
|
|
m_nXCastDisplacement = -((double)textRect.bottom / tan(dRadDirection));
|
|
m_nYCastDisplacement = textRect.bottom;
|
|
}
|
|
else if ( m_nScrollDirection > 90 && m_nScrollDirection <= 180 - angle )
|
|
{
|
|
m_nXCastDisplacement = ((double)textRect.bottom / tan(OX_PI - dRadDirection));
|
|
m_nYCastDisplacement = textRect.bottom;
|
|
}
|
|
else if ( m_nScrollDirection > 180-angle && m_nScrollDirection <= 180 )
|
|
{
|
|
m_nXCastDisplacement = textRect.right;
|
|
m_nYCastDisplacement = ((double)textRect.right * tan(OX_PI - dRadDirection));
|
|
}
|
|
else if ( m_nScrollDirection > 180 && m_nScrollDirection <= 180 + angle )
|
|
{
|
|
m_nXCastDisplacement = textRect.right;
|
|
m_nYCastDisplacement = -((double)textRect.right * tan(dRadDirection));
|
|
}
|
|
else if ( m_nScrollDirection > 180+angle && m_nScrollDirection <= 270 )
|
|
{
|
|
m_nXCastDisplacement = ((double)textRect.bottom / tan(dRadDirection));
|
|
m_nYCastDisplacement = -textRect.bottom;
|
|
}
|
|
else if ( m_nScrollDirection > 270 && m_nScrollDirection <= 360-angle )
|
|
{
|
|
m_nXCastDisplacement = -((double)textRect.bottom / tan(OX_PI - dRadDirection));
|
|
m_nYCastDisplacement = -textRect.bottom;
|
|
}
|
|
else
|
|
{
|
|
m_nXCastDisplacement = -textRect.right;
|
|
m_nYCastDisplacement = -((double)textRect.right * tan(OX_PI - dRadDirection));
|
|
}
|
|
}
|
|
|
|
BOOL COXStaticText::RebuildFont()
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns : TRUE - if the function succeeds; otherwise FALSE.
|
|
// --- Effect : Rebuilds the font object.
|
|
{
|
|
if((HFONT)*m_pObjFont!=NULL)
|
|
m_pObjFont->DeleteObject();
|
|
return m_pObjFont->CreateFontIndirect(&m_LogFont);
|
|
}
|
|
|
|
BOOL COXStaticText::OnEraseBkgnd(CDC* pDC)
|
|
{
|
|
UNREFERENCED_PARAMETER(pDC);
|
|
return TRUE;
|
|
}
|
|
|
|
void COXStaticText::OnPaint()
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : The framework calls this member function when Windows or an application
|
|
// makes a request to repaint a portion of an application's window.
|
|
{
|
|
CSingleLock RedrawLock(m_pCritSecRedrawWait);
|
|
RedrawLock.Lock();
|
|
|
|
m_dwBeginTickCount = ::GetTickCount();
|
|
|
|
CPaintDC dc(this); // Device context for painting.
|
|
|
|
CDC memDC; // Compatible memory device context.
|
|
CRect textRect; // Client coordinates of the window client area.
|
|
CDC drawDC;
|
|
CBitmap drawBMP;
|
|
|
|
GetClientRect(&textRect);
|
|
|
|
if (!memDC.CreateCompatibleDC(&dc)) // Create compatible memory device context
|
|
{
|
|
TRACE(_T("OnPaint() - memDC.CreateCompatibleDC() failed\n"));
|
|
RedrawLock.Unlock();
|
|
return;
|
|
}
|
|
int nSavedDC=memDC.SaveDC();
|
|
memDC.SelectObject(m_BMP);
|
|
|
|
if (!drawDC.CreateCompatibleDC(&dc)) // Create compatible memory device context
|
|
{
|
|
RedrawLock.Unlock();
|
|
return;
|
|
}
|
|
int nSavedDC2=drawDC.SaveDC();
|
|
if (drawBMP.CreateCompatibleBitmap( &dc, textRect.Width(), textRect.Height()))
|
|
{
|
|
CBitmap* pOldDrawBitmap = drawDC.SelectObject(&drawBMP);
|
|
|
|
if(m_dwBkColor!=CLR_NONE)
|
|
drawDC.FillSolidRect(&textRect, drawDC.GetNearestColor(m_dwBkColor));
|
|
else
|
|
SendMessage(WM_ERASEBKGND,(WPARAM)((HDC)drawDC),NULL);
|
|
|
|
drawDC.BitBlt( (int)(m_nXDisplacement-m_szTextSize.cx/2+0.5),
|
|
(int)(m_nYDisplacement-m_szTextSize.cy/2+0.5), m_szTextSize.cx,
|
|
m_szTextSize.cy, &memDC, 0, 0, SRCCOPY);
|
|
|
|
CPoint secPt;
|
|
if( (m_nXDisplacement + m_szTextSize.cx/2 >= textRect.right+m_szGapSize.cx) ||
|
|
(m_nXDisplacement - m_szTextSize.cx/2 < textRect.left-m_szGapSize.cx) ||
|
|
(m_nYDisplacement + m_szTextSize.cy/2 >= textRect.bottom+m_szGapSize.cy) ||
|
|
(m_nYDisplacement - m_szTextSize.cy/2 < textRect.top-m_szGapSize.cy))
|
|
{
|
|
secPt.x = (long)(m_nXDisplacement + m_nXCastDisplacement + 0.5);
|
|
secPt.y = (long)(m_nYDisplacement + m_nYCastDisplacement + 0.5);
|
|
drawDC.BitBlt( secPt.x-m_szTextSize.cx/2, secPt.y-m_szTextSize.cy/2,
|
|
m_szTextSize.cx, m_szTextSize.cy, &memDC, 0, 0, SRCCOPY);
|
|
}
|
|
|
|
dc.BitBlt( 0, 0, textRect.Width(), textRect.Height(), &drawDC, 0, 0, SRCCOPY);
|
|
|
|
// Clean Up
|
|
|
|
if (pOldDrawBitmap != NULL)
|
|
drawDC.SelectObject(pOldDrawBitmap);
|
|
}
|
|
else
|
|
{
|
|
TRACE(_T("OnPaint() - drawDC.CreateCompatibleBitmap() failed\n"));
|
|
}
|
|
|
|
// Clean Up
|
|
if(nSavedDC2)
|
|
drawDC.RestoreDC(nSavedDC2);
|
|
|
|
drawBMP.DeleteObject();
|
|
|
|
if(nSavedDC)
|
|
memDC.RestoreDC(nSavedDC);
|
|
|
|
m_dwEndTickCount = ::GetTickCount();
|
|
m_dwLastTickDelta = m_dwCurrentTickDelta;
|
|
m_dwCurrentTickDelta = m_dwEndTickCount - m_dwBeginTickCount;
|
|
|
|
if (m_bAllowRefresh
|
|
&& !(m_dwCurrentTickDelta == 0 && m_dwLastTickDelta == 0)
|
|
&& (m_dwCurrentTickDelta >= (2 * m_dwLastTickDelta)
|
|
|| m_dwLastTickDelta >= (2 * m_dwCurrentTickDelta)))
|
|
{
|
|
RefreshBitmap();
|
|
m_bAllowRefresh = FALSE;
|
|
}
|
|
else
|
|
m_bAllowRefresh = TRUE;
|
|
|
|
RedrawLock.Unlock();
|
|
}
|
|
|
|
void COXStaticText::OnDestroy()
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns :
|
|
// --- Effect : The framework calls this member function to inform the CWnd object that it is
|
|
// being destroyed. OnDestroy is called after the CWnd object is removed from the screen.
|
|
// This function stops text scrolling and terminates the window redrawing thread.
|
|
{
|
|
CStatic::OnDestroy();
|
|
StartScrolling(FALSE);
|
|
}
|
|
|
|
LRESULT COXStaticText::OnPrepareBitmap(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns : TRUE is successful
|
|
// --- Effect : Prepares the text bitmap for drawing
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
BOOL bNow = (BOOL)wParam;
|
|
if (!bNow)
|
|
return TRUE;
|
|
|
|
CSingleLock RedrawLock(m_pCritSecRedrawWait);
|
|
RedrawLock.Lock();
|
|
|
|
CClientDC dc(this);
|
|
if(m_dwBkColor==CLR_NONE)
|
|
SendMessage(WM_ERASEBKGND,(WPARAM)((HDC)dc),NULL);
|
|
|
|
CRect textRect;
|
|
CDC memDC;
|
|
|
|
GetClientRect(&textRect);
|
|
|
|
if (!memDC.CreateCompatibleDC(&dc)) // Create compatible memory device context
|
|
{
|
|
TRACE(_T("OnPrepareBitmap() - memDC.CreateCompatibleDC() failed\n"));
|
|
RedrawLock.Unlock();
|
|
return FALSE;
|
|
}
|
|
int nSavedDC=memDC.SaveDC();
|
|
memDC.OffsetViewportOrg(0, 0);
|
|
::SetGraphicsMode(memDC.m_hDC, m_nGraphicsMode);
|
|
CFont* pOldFont = memDC.SelectObject(m_pObjFont);
|
|
memDC.SetBkMode(TRANSPARENT);
|
|
|
|
if (m_sTextNarrow.IsEmpty())
|
|
GetWindowText(m_sText);
|
|
|
|
|
|
EllipsesReplace(&memDC, &textRect);
|
|
m_szTextSize = CalcRectSizes(&memDC);
|
|
|
|
CRect rc(CPoint(0,0),m_szTextSize);
|
|
m_szTextSize.cx += m_dwOffset;
|
|
m_szTextSize.cy += m_dwOffset;
|
|
CRect rcText( CPoint( 0, 0), m_szTextSize);
|
|
|
|
if(m_BMP != NULL)
|
|
{
|
|
delete m_BMP;
|
|
m_BMP=NULL;
|
|
}
|
|
try
|
|
{
|
|
m_BMP = new CBitmap();
|
|
}
|
|
catch(CMemoryException* e)
|
|
{
|
|
delete e;
|
|
m_BMP=NULL;
|
|
TRACE(_T("OnPrepareBitmap() - m_BMP = new CBitmap() failed\n"));
|
|
RedrawLock.Unlock();
|
|
return FALSE;
|
|
}
|
|
|
|
if(!m_BMP->CreateCompatibleBitmap( &dc, m_szTextSize.cx, m_szTextSize.cy))
|
|
{
|
|
delete m_BMP;
|
|
m_BMP = NULL;
|
|
TRACE(_T("OnPrepareBitmap() - m_BMP->CreateCompatibleBitmap failed\n"));
|
|
RedrawLock.Unlock();
|
|
return FALSE;
|
|
}
|
|
|
|
CBitmap* pOldBMP= memDC.SelectObject(m_BMP);
|
|
|
|
if(m_dwBkColor!=CLR_NONE)
|
|
memDC.FillSolidRect(&rcText, memDC.GetNearestColor(m_dwBkColor));
|
|
else
|
|
SendMessage(WM_ERASEBKGND,(WPARAM)((HDC)memDC),NULL);
|
|
|
|
TextOutput(&memDC, rc);
|
|
|
|
if (pOldBMP != NULL)
|
|
memDC.SelectObject(pOldBMP);
|
|
|
|
if (pOldFont != NULL)
|
|
memDC.SelectObject(pOldFont);
|
|
|
|
if(nSavedDC)
|
|
memDC.RestoreDC(nSavedDC);
|
|
|
|
GetInitialDisplacement(textRect);
|
|
|
|
ScrollAmountRecalc();
|
|
|
|
RedrawLock.Unlock();
|
|
RedrawWindow();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL COXStaticText::RefreshBitmap()
|
|
{
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns : TRUE is successful
|
|
// --- Effect : Prepares the text bitmap for drawing
|
|
|
|
|
|
CClientDC dc(this);
|
|
if(m_dwBkColor==CLR_NONE)
|
|
SendMessage(WM_ERASEBKGND,(WPARAM)((HDC)dc),NULL);
|
|
|
|
CRect textRect;
|
|
CDC memDC;
|
|
|
|
GetClientRect(&textRect);
|
|
|
|
if (!memDC.CreateCompatibleDC(&dc)) // Create compatible memory device context
|
|
{
|
|
TRACE(_T("RefreshBitmap() - memDC.CreateCompatibleDC() failed\n"));
|
|
return FALSE;
|
|
}
|
|
int nSavedDC=memDC.SaveDC();
|
|
memDC.OffsetViewportOrg(0, 0);
|
|
::SetGraphicsMode(memDC.m_hDC, m_nGraphicsMode);
|
|
CFont* pOldFont = memDC.SelectObject(m_pObjFont);
|
|
memDC.SetBkMode(TRANSPARENT);
|
|
|
|
if (m_sTextNarrow.IsEmpty())
|
|
GetWindowText(m_sText);
|
|
|
|
|
|
EllipsesReplace(&memDC, &textRect);
|
|
m_szTextSize = CalcRectSizes(&memDC);
|
|
|
|
CRect rc(CPoint(0,0),m_szTextSize);
|
|
m_szTextSize.cx += m_dwOffset;
|
|
m_szTextSize.cy += m_dwOffset;
|
|
CRect rcText( CPoint( 0, 0), m_szTextSize);
|
|
|
|
if(m_BMP != NULL)
|
|
{
|
|
delete m_BMP;
|
|
m_BMP=NULL;
|
|
}
|
|
try
|
|
{
|
|
m_BMP = new CBitmap();
|
|
}
|
|
catch(CMemoryException* e)
|
|
{
|
|
delete e;
|
|
m_BMP=NULL;
|
|
TRACE(_T("RefreshBitmap() - m_BMP = new CBitmap() failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
if(!m_BMP->CreateCompatibleBitmap( &dc, m_szTextSize.cx, m_szTextSize.cy))
|
|
{
|
|
delete m_BMP;
|
|
m_BMP = NULL;
|
|
TRACE(_T("RefreshBitmap() - m_BMP->CreateCompatibleBitmap failed\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
CBitmap* pOldBMP= memDC.SelectObject(m_BMP);
|
|
|
|
if(m_dwBkColor!=CLR_NONE)
|
|
memDC.FillSolidRect(&rcText, memDC.GetNearestColor(m_dwBkColor));
|
|
else
|
|
SendMessage(WM_ERASEBKGND,(WPARAM)((HDC)memDC),NULL);
|
|
|
|
TextOutput(&memDC, rc);
|
|
|
|
if (pOldBMP != NULL)
|
|
memDC.SelectObject(pOldBMP);
|
|
|
|
if (pOldFont != NULL)
|
|
memDC.SelectObject(pOldFont);
|
|
|
|
if(nSavedDC)
|
|
memDC.RestoreDC(nSavedDC);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT COXStaticText::OnDisplayChange(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
return PrepareBitmap(TRUE);
|
|
}
|
|
|
|
void COXStaticText::SpeedCalc(DWORD dwScrollSpeed, DWORD* pdwTimeOut, DWORD* pdwAmount)
|
|
// --- In : dwScrollSpeed - text scrolling speed (pixels per second).
|
|
// --- Out : pdwTimeOut - pointer to the scroll time out interval (ms).
|
|
// pdwAmount - pointer to the scroll amount (pixels).
|
|
// --- Returns :
|
|
// --- Effect : Calculates optimal time out interval and scroll amount values.
|
|
// These values give amount/time_out ratio that is nearest to specified speed.
|
|
{
|
|
DWORD dwSpeed, dwSpeedBest = dwScrollSpeed,
|
|
dwTimeOut, dwTimeOutBest = 0,
|
|
dwAmount, dwAmountBest = 0;
|
|
|
|
for ( dwAmount = 1; dwAmount < dwScrollSpeed; dwAmount++ )
|
|
{
|
|
for ( dwTimeOut = m_dwMinTimeOut; dwTimeOut < 1000 ; dwTimeOut++ )
|
|
{
|
|
dwSpeed = dwScrollSpeed - 1000 * dwAmount / dwTimeOut;
|
|
if ( dwSpeed < dwSpeedBest )
|
|
{
|
|
dwSpeedBest = dwSpeed;
|
|
dwTimeOutBest = dwTimeOut;
|
|
dwAmountBest = dwAmount;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !dwTimeOutBest || !dwAmountBest || dwSpeedBest > dwScrollSpeed / 6 )
|
|
{
|
|
dwTimeOutBest = 1000;
|
|
dwAmountBest = dwScrollSpeed;
|
|
}
|
|
|
|
*pdwTimeOut = dwTimeOutBest;
|
|
*pdwAmount = dwAmountBest;
|
|
}
|
|
|
|
BOOL COXStaticText::PrepareBitmap(BOOL bNow)
|
|
// --- In :
|
|
// --- Out :
|
|
// --- Returns : TRUE is successful
|
|
// --- Effect : Sends message to CWnd object to prepare the text bitmap for drawing
|
|
{
|
|
return ((BOOL)SendMessage(m_nPrepareBitmap,(WPARAM)(bNow),NULL));
|
|
}
|
|
|
|
CSize COXStaticText::CalcRectSizes(CDC* pDC)
|
|
{
|
|
CSize size;
|
|
::GetTextExtentPoint32(pDC->m_hDC, (LPCTSTR)m_sTextNarrow,
|
|
m_sTextNarrow.GetLength(), &size);
|
|
|
|
double x1, x2, y1, y2;
|
|
double alpha = ((GetGraphicsMode()==GM_ADVANCED) ?
|
|
GetCharAngle() : GetStringAngle())/10;
|
|
alpha = alpha * 3.1415926/180.0;
|
|
|
|
x1= size.cx * cos(alpha);
|
|
x2= size.cy * sin(alpha);
|
|
|
|
y1= size.cx * sin(alpha);
|
|
y2= size.cy * cos(alpha);
|
|
|
|
CSize szRet;
|
|
szRet.cx = (int)(absolute(x1) + absolute(x2) + 0.5) +
|
|
m_rectViewMargins.left + m_rectViewMargins.right;
|
|
szRet.cy = (int)(absolute(y1) + absolute(y2) + 0.5) +
|
|
m_rectViewMargins.top + m_rectViewMargins.bottom;
|
|
|
|
return szRet;
|
|
}
|
|
|
|
void COXStaticText::GetInitialDisplacement(CRect& textRect)
|
|
{
|
|
switch(m_nHorzAlignment)
|
|
{
|
|
case OX_ALIGNHORZ_LEFT:
|
|
{
|
|
m_nXDisplacement = m_szTextSize.cx/2;
|
|
break;
|
|
}
|
|
case OX_ALIGNHORZ_CENTER:
|
|
{
|
|
m_nXDisplacement = textRect.Width()/2;
|
|
break;
|
|
}
|
|
case OX_ALIGNHORZ_RIGHT:
|
|
{
|
|
m_nXDisplacement = textRect.Width() - m_szTextSize.cx/2 - 1;
|
|
break;
|
|
}
|
|
}
|
|
switch(m_nVertAlignment)
|
|
{
|
|
case OX_ALIGNVERT_TOP:
|
|
{
|
|
m_nYDisplacement = m_szTextSize.cy/2;
|
|
break;
|
|
}
|
|
case OX_ALIGNVERT_CENTER:
|
|
{
|
|
m_nYDisplacement = textRect.Height()/2;
|
|
break;
|
|
}
|
|
case OX_ALIGNVERT_BOTTOM:
|
|
{
|
|
m_nYDisplacement = textRect.Height() - m_szTextSize.cy/2 - 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|