SmoothView.h
class CSmoothView : public CScrollView
{
protected: // create from serialization only
CFont m_font;
CPalette m_palette;
int m_nImageHeight;
int m_nImageWidth;
CBitmap m_bitmap;
void InitScrollSizes ();
int m_nLineSlices;
int m_nPageSlices;
DWORD m_dwMinTime;
CSmoothView();
DECLARE_DYNCREATE(CSmoothView)
// Attributes
public:
void DoPaletteChanged ();
BOOL DoQueryNewPalette ();
CSmoothDoc* GetDocument();
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSmoothView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL OnScroll(UINT nScrollCode, UINT nPos,
BOOL bDoScroll = TRUE);
protected:
virtual void OnInitialUpdate(); // called first time after construct
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CSmoothView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CSmoothView)
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in SmoothView.cpp
inline CSmoothDoc* CSmoothView::GetDocument()
{ return (CSmoothDoc*)m_pDocument; }
#endif
SmoothView.cpp
#include "stdafx.h"
#include "Smooth.h"
#include "SmoothDoc.h"
#include "SmoothView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
///////////////////////////////////////////////////////////////////////
// CSmoothView
IMPLEMENT_DYNCREATE(CSmoothView, CScrollView)
BEGIN_MESSAGE_MAP(CSmoothView, CScrollView)
//{{AFX_MSG_MAP(CSmoothView)
ON_WM_SIZE()
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////
// CSmoothView construction/destruction
CSmoothView::CSmoothView()
{
m_dwMinTime = 10; // Minimum delay time in milliseconds
m_nPageSlices = 12; // Number of scroll subdivisions per page
m_nLineSlices = 4; // Number of scroll subdivisions per line
m_nImageWidth = 0;
m_nImageHeight = 0;
}
CSmoothView::~CSmoothView()
{
}
BOOL CSmoothView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CScrollView::PreCreateWindow(cs);
}
///////////////////////////////////////////////////////////////////////
// CSmoothView drawing
void CSmoothView::OnDraw(CDC* pDC)
{
CSmoothDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//
// Realize a palette if this is a palettized output device.
//
CPalette* pOldPalette= NULL;
if (m_palette.m_hObject != NULL) {
pOldPalette = pDC->SelectPalette (&m_palette, FALSE);
pDC->RealizePalette ();
}
//
// Paint the window background with the bitmap.
//
CDC memoryDC;
memoryDC.CreateCompatibleDC (pDC);
CBitmap* pOldBitmap = memoryDC.SelectObject (&m_bitmap);
CRect rect;
pDC->GetClipBox (&rect);
int nStartCol = rect.left / m_nImageWidth;
int nEndCol = (rect.right + m_nImageWidth + 1) / m_nImageWidth;
int nStartRow = rect.top / m_nImageHeight;
int nEndRow = (rect.bottom + m_nImageHeight + 1) / m_nImageHeight;
for (int i=nStartCol; i<nEndCol; i++) {
for (int j=nStartRow; j<nEndRow; j++) {
int x = i * m_nImageWidth;
int y = j * m_nImageHeight;
pDC->BitBlt (x, y, m_nImageWidth, m_nImageHeight,
&memoryDC, 0, 0, SRCCOPY);
}
}
memoryDC.SelectObject (pOldBitmap);
//
// Draw a string of text that floats above the background.
//
pDC->SetBkMode (TRANSPARENT);
CFont* pOldFont = pDC->SelectObject (&m_font);
CString string = "Smooth scrolling is cool!";
rect.SetRect (0, 0, 1024, 1024);
rect.OffsetRect (6, 6);
pDC->SetTextColor (RGB (192, 192, 192));
pDC->DrawText (string, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
rect.SetRect (0, 0, 1024, 1024);
pDC->SetTextColor (RGB (0, 0, 0));
pDC->DrawText (string, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);
pDC->SelectObject (pOldFont);
//
// Deselect the palette that was selected in earlier.
//
if (pOldPalette != NULL)
pDC->SelectPalette (pOldPalette, FALSE);
}
void CSmoothView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate ();
InitScrollSizes ();
}
///////////////////////////////////////////////////////////////////////
// CSmoothView diagnostics
#ifdef _DEBUG
void CSmoothView::AssertValid() const
{
CScrollView::AssertValid();
}
void CSmoothView::Dump(CDumpContext& dc) const
{
CScrollView::Dump(dc);
}
CSmoothDoc* CSmoothView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSmoothDoc)));
return (CSmoothDoc*)m_pDocument;
}
#endif //_DEBUG
///////////////////////////////////////////////////////////////////////
// CSmoothView message handlers
BOOL CSmoothView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
{
//
// First handle left/right scroll messages. If scrolling by page,
// scroll m_nPageSlices times rather than 1. If scrolling by line,
// scroll m_nLineSlices times.
//
BYTE nCode = LOBYTE (nScrollCode);
if ((nCode == SB_PAGELEFT) || (nCode == SB_PAGERIGHT) ||
(nCode == SB_LINELEFT) || (nCode == SB_LINERIGHT)) {
int nCount, nInc, nFinalInc, nLineCode;
switch (nCode) {
case SB_PAGELEFT:
nLineCode = SB_LINELEFT;
nInc = m_pageDev.cx / m_nPageSlices;
nFinalInc = m_pageDev.cx % m_nPageSlices;
nCount = m_nPageSlices;
break;
case SB_PAGERIGHT:
nLineCode = SB_LINERIGHT;
nInc = m_pageDev.cx / m_nPageSlices;
nFinalInc = m_pageDev.cx % m_nPageSlices;
nCount = m_nPageSlices;
break;
case SB_LINELEFT:
nLineCode = SB_LINELEFT;
nInc = m_lineDev.cx / m_nLineSlices;
nFinalInc = m_lineDev.cx % m_nLineSlices;
nCount = m_nLineSlices;
break;
case SB_LINERIGHT:
nLineCode = SB_LINERIGHT;
nInc = m_lineDev.cx / m_nLineSlices;
nFinalInc = m_lineDev.cx % m_nLineSlices;
nCount = m_nLineSlices;
break;
}
int nOldLineSize = m_lineDev.cx;
BOOL bResult = FALSE;
DWORD dwTime = 0;
while (nCount--) {
DWORD dwCurrentTime = ::GetCurrentTime ();
DWORD dwElapsedTime = dwCurrentTime - dwTime;
if (dwElapsedTime < m_dwMinTime)
::Sleep (m_dwMinTime - dwElapsedTime);
dwTime = dwCurrentTime;
m_lineDev.cx = nInc;
BOOL bScrolled =
CScrollView::OnScroll (MAKEWORD (nLineCode, -1), nPos);
m_lineDev.cx = nOldLineSize;
if (!bScrolled)
return bResult;
bResult = TRUE;
}
if (nFinalInc) {
m_lineDev.cx = nFinalInc;
if (!CScrollView::OnScroll (MAKEWORD (nLineCode, -1), nPos))
bResult = TRUE;
m_lineDev.cx = nOldLineSize;
}
return bResult;
}
//
// Next handle up/down scroll messages. If scrolling by page,
// scroll m_nPageSlices times rather than 1. If scrolling by line,
// scroll m_nLineSlices times.
//
nCode = HIBYTE (nScrollCode);
if ((nCode == SB_PAGEUP) || (nCode == SB_PAGEDOWN) ||
(nCode == SB_LINEUP) || (nCode == SB_LINEDOWN)) {
int nCount, nInc, nFinalInc, nLineCode;
switch (nCode) {
case SB_PAGEUP:
nLineCode = SB_LINEUP;
nInc = m_pageDev.cy / m_nPageSlices;
nFinalInc = m_pageDev.cy % m_nPageSlices;
nCount = m_nPageSlices;
break;
case SB_PAGEDOWN:
nLineCode = SB_LINEDOWN;
nInc = m_pageDev.cy / m_nPageSlices;
nFinalInc = m_pageDev.cy % m_nPageSlices;
nCount = m_nPageSlices;
break;
case SB_LINEUP:
nLineCode = SB_LINEUP;
nInc = m_lineDev.cy / m_nLineSlices;
nFinalInc = m_lineDev.cy % m_nLineSlices;
nCount = m_nLineSlices;
break;
case SB_LINEDOWN:
nLineCode = SB_LINEDOWN;
nInc = m_lineDev.cy / m_nLineSlices;
nFinalInc = m_lineDev.cy % m_nLineSlices;
nCount = m_nLineSlices;
break;
}
int nOldLineSize = m_lineDev.cy;
BOOL bResult = FALSE;
DWORD dwTime = 0;
while (nCount--) {
DWORD dwCurrentTime = ::GetCurrentTime ();
DWORD dwElapsedTime = dwCurrentTime - dwTime;
if (dwElapsedTime < m_dwMinTime)
::Sleep (m_dwMinTime - dwElapsedTime);
dwTime = dwCurrentTime;
m_lineDev.cy = nInc;
BOOL bScrolled =
CScrollView::OnScroll (MAKEWORD (-1, nLineCode), nPos);
m_lineDev.cy = nOldLineSize;
if (!bScrolled)
return bResult;
bResult = TRUE;
}
if (nFinalInc) {
m_lineDev.cy = nFinalInc;
if (!CScrollView::OnScroll (MAKEWORD (-1, nLineCode), nPos))
bResult = TRUE;
m_lineDev.cy = nOldLineSize;
}
return bResult;
}
//
// If we make it to here, the scroll message wasn't handled above.
// Call the base class's OnScroll function and let it do the work.
//
return CScrollView::OnScroll (nScrollCode, nPos, bDoScroll);
}
void CSmoothView::OnSize(UINT nType, int cx, int cy)
{
CScrollView::OnSize (nType, cx, cy);
InitScrollSizes ();
}
void CSmoothView::InitScrollSizes ()
{
CRect rect;
GetClientRect (&rect);
int nHPageSize = (rect.Width () * 9) / 10;
int nVPageSize = (rect.Height () * 9) / 10;
int nHLineSize = nHPageSize / 10;
int nVLineSize = nVPageSize / 10;
SetScrollSizes (MM_TEXT,
CSize (1024, 1024),
CSize (nHPageSize, nVPageSize),
CSize (nHLineSize, nVLineSize));
}
int CSmoothView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CScrollView::OnCreate(lpCreateStruct) == -1)
return -1;
//
// Load the background bitmap.
//
HANDLE hBitmap = ::LoadImage (AfxGetInstanceHandle (),
MAKEINTRESOURCE (IDB_BITMAP), IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION);
ASSERT (hBitmap != NULL);
m_bitmap.Attach (hBitmap);
BITMAP bm;
m_bitmap.GetObject (sizeof (bm), &bm);
m_nImageWidth = bm.bmWidth;
m_nImageHeight = bm.bmHeight;
//
// Create a gray scale palette for the bitmap (if needed).
//
CClientDC dc (this);
if (dc.GetDeviceCaps (RASTERCAPS) & RC_PALETTE) {
UINT nSize = sizeof (LOGPALETTE) + (sizeof (PALETTEENTRY) * 31);
LOGPALETTE* plp = (LOGPALETTE*) new BYTE[nSize];
plp->palVersion = 0x300;
plp->palNumEntries = 32;
for (int i=0; i<32; i++) {
plp->palPalEntry[i].peRed = i * 8;
plp->palPalEntry[i].peGreen = i * 8;
plp->palPalEntry[i].peBlue = i * 8;
plp->palPalEntry[i].peFlags = 0;
}
m_palette.CreatePalette (plp);
ASSERT_VALID (&m_palette);
delete[] plp;
}
//
// Create a 36-point bold Times New Roman font.
//
LOGFONT lf;
::ZeroMemory (&lf, sizeof (lf));
lf.lfHeight = 360;
lf.lfWeight = FW_BOLD;
lf.lfItalic = TRUE;
::lstrcpy (lf.lfFaceName, "Times New Roman");
m_font.CreatePointFontIndirect (&lf);
return 0;
}
BOOL CSmoothView::DoQueryNewPalette ()
{
//
// This function is called when the application's main frame window
// receives a WM_QUERYNEWPALETTE message.
//
if (m_palette.m_hObject == NULL)
return 0;
CClientDC dc (this);
CPalette* pOldPalette = dc.SelectPalette (&m_palette, FALSE);
UINT nCount;
if (nCount = dc.RealizePalette ())
Invalidate ();
dc.SelectPalette (pOldPalette, FALSE);
return nCount;
}
void CSmoothView::DoPaletteChanged ()
{
//
// This function is called when the application's main frame window
// receives a WM_PALETTECHANGED message.
//
if (m_palette.m_hObject != NULL) {
CClientDC dc (this);
CPalette* pOldPalette = dc.SelectPalette (&m_palette, FALSE);
if (dc.RealizePalette ())
Invalidate ();
dc.SelectPalette (pOldPalette, FALSE);
}
}