Figure 2 Key CDocument Operations
Function | Description |
GetFirstViewPosition | Returns a POSITION value that can be passed to GetNextView to enumerate the document's views. |
GetNextView | Returns a CView pointer to the next view in the list of views attached to this document. |
GetPathName | Retrieves the document's file name and path-for example, "C:\Documents\Personal\MyFile.Lif." Returns a null string if the document has not been named. |
GetTitle | Retrieves the document's title-for example, "MyFile." Returns a null string if the document has not been named. |
IsModified | Returns a nonzero value if the document contains unsaved data, and 0 if it does not. |
SetModifiedFlag | Sets or clears the document's modified flag. |
UpdateAllViews | Updates all views associated with the document by calling each view's OnUpdate function. |
OnFileSendMail | Implements the Send Mail command in the File menu. |
Figure 3 Key CDocument Overridables
Function | Description |
OnNewDocument | Called by the framework when a new document is created. Override to reinitialize the document object when a new document is created. |
OnOpenDocument | Called by the framework when a document is loaded from disk. Override to reinitialize the unserialized data members of the document object before a new document is loaded. |
DeleteContents | Called by the framework to delete the document's contents. Override to free memory and other resources allocated to a document before it is closed. |
Serialize | Called by the framework to serialize a document to or from disk. Override to provide document-specific serialization code so your documents can be loaded and saved. |
Figure 5 Key Predefined Command IDs and Command Handlers
Command ID | Menu Item Name | Default Implementation | Prewired? |
File menu | |||
ID_FILE_NEW | New | CWinApp::OnFileNew | No |
ID_FILE_OPEN | Open | CWinApp::OnFileOpen | No |
ID_FILE_CLOSE | Close | CDocument::OnFileClose | Yes |
ID_FILE_SAVE | Save | CDocument::OnFileSave | Yes |
ID_FILE_SAVE_AS | Save As | CDocument::OnFileSaveAs | Yes |
ID_FILE_PAGE_SETUP | Page Setup | None | N/A |
ID_FILE_PRINT_SETUP | Print Setup | CWinApp::OnFilePrintSetup | No |
ID_FILE_PRINT | CView::OnFilePrint | No | |
ID_FILE_PRINT_PREVIEW | Print Preview | CView::OnFilePrintPreview | No |
ID_FILE_SEND_MAIL | Send Mail | CDocument::OnFileSendMail | No |
ID_FILE_MRU_FILE1-16 | N/A | CWinApp::OnOpenRecentFile | Yes |
ID_APP_EXIT | Exit | CWinApp::OnAppExit | Yes |
Edit menu | |||
ID_EDIT_CLEAR | Clear | None* | N/A |
ID_EDIT_CLEAR_ALL | Clear All | None | N/A |
ID_EDIT_COPY | Copy | None* | N/A |
ID_EDIT_CUT | Cut | None* | N/A |
ID_EDIT_PASTE | Paste | None* | N/A |
ID_EDIT_PASTE_LINK | Paste Link | None | N/A |
ID_EDIT_PASTE_SPECIAL | Paste Special | None | N/A |
ID_EDIT_FIND | Find | None* | N/A |
ID_EDIT_REPLACE | Replace | None* | N/A |
ID_EDIT_REPEAT | Repeat | None* | N/A |
ID_EDIT_SELECT_ALL | Select All | None* | N/A |
ID_EDIT_UNDO | Undo | None* | N/A |
ID_EDIT_REDO | Redo | None | N/A |
View menu | |||
ID_VIEW_TOOLBAR | Toolbar | CFrameWnd::OnBarCheck | Yes |
ID_VIEW_STATUS_BAR | Status Bar | CFrameWnd::OnBarCheck | Yes |
Window menu | |||
ID_WINDOW_NEW | New Window | CMDIFrameWnd::OnWindowNew | Yes |
ID_WINDOW_ARRANGE | Arrange Icons | CMDIFrameWnd::OnMDIWindowCmd | Yes |
ID_WINDOW_CASCADE | Cascade | CMDIFrameWnd::OnMDIWindowCmd | Yes |
ID_WINDOW_TILE_HORZ | Tile Horizontal | CMDIFrameWnd::OnMDIWindowCmd | Yes |
ID_WINDOW_TILE_VERT | Tile Vertical | CMDIFrameWnd::OnMDIWindowCmd | Yes |
ID_WINDOW_SPLIT | Split | CView::OnSplitCmd | Yes |
Help menu | |||
ID_APP_ABOUT | About AppName | None | N/A |
* CEditView and CRichEditView provide default implementations and message-map entries for these commands |
Figure 6 Life
RESOURCE.H
//***************************************************************************
//
// Resource.h (Life)
//
//***************************************************************************
#define ID_OPTIONS_STEP 100
#define ID_OPTIONS_OPEN_BOUNDARY 101
#define ID_OPTIONS_CLOSED_BOUNDARY 102
#define IDC_ICONRECT 200
#define IDC_HORZ 210
#define IDC_VERT 211
#define IDR_MAINFRAME 300
#define CELLWIDTH 16
#define CELLHEIGHT 16
LIFE.RC
//***************************************************************************
//
// Life.rc
//
//***************************************************************************
#include <afxres.h>
#include "Resource.h"
IDR_MAINFRAME ICON Life.ico
GrayCell BITMAP GrayCell.bmp
BlueCell BITMAP BlueCell.bmp
IDR_MAINFRAME MENU
BEGIN
POPUP "&File" {
MENUITEM "&New\tCtrl+N", ID_FILE_NEW
MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN
MENUITEM SEPARATOR
MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE
MENUITEM "Save &As...\tCtrl+A", ID_FILE_SAVE_AS
MENUITEM SEPARATOR
MENUITEM "Recent File", ID_FILE_MRU_FILE1
MENUITEM SEPARATOR
MENUITEM "E&xit", ID_APP_EXIT
}
POPUP "&Options" {
MENUITEM "Ste&p\tF10", ID_OPTIONS_STEP
MENUITEM SEPARATOR
MENUITEM "&Open Boundary", ID_OPTIONS_OPEN_BOUNDARY
MENUITEM "Closed Boundary", ID_OPTIONS_CLOSED_BOUNDARY
}
POPUP "&View" {
MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR
}
POPUP "&Help" {
MENUITEM "&About Life...", ID_APP_ABOUT
}
END
IDR_MAINFRAME ACCELERATORS
BEGIN
"N", ID_FILE_NEW, VIRTKEY, CONTROL
"O", ID_FILE_OPEN, VIRTKEY, CONTROL
"S", ID_FILE_SAVE, VIRTKEY, CONTROL
"A", ID_FILE_SAVE_AS, VIRTKEY, CONTROL
VK_F10, ID_OPTIONS_STEP, VIRTKEY
END
STRINGTABLE
BEGIN
IDR_MAINFRAME "Life\n\n\nLife Grids (*.lif)\n.lif\nLife.Grid\nLife Grid"
END
STRINGTABLE
BEGIN
AFX_IDS_IDLEMESSAGE "Ready"
ID_OPTIONS_STEP "Evolve the grid one generation"
ID_OPTIONS_OPEN_BOUNDARY "Enable wrap-around boundaries"
ID_OPTIONS_CLOSED_BOUNDARY "Disable wrap-around boundaries"
END
GridSize DIALOG 0, 0, 148, 60
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Grid Size"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "&Horizontal", -1, 12, 16, 40, 8
LTEXT "&Vertical", -1, 12, 36, 40, 8
EDITTEXT IDC_HORZ, 56, 12, 32, 12, ES_AUTOHSCROLL
EDITTEXT IDC_VERT, 56, 32, 32, 12, ES_AUTOHSCROLL
DEFPUSHBUTTON "OK", IDOK, 100, 12, 40, 12, WS_GROUP
END
About DIALOG 0, 0, 256, 98
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "About Life"
FONT 8, "MS Sans Serif"
BEGIN
LTEXT "", IDC_ICONRECT, 14, 12, 80, 74
LTEXT "Life Version 1.0", -1, 108, 12, 136, 8
LTEXT "From the book", -1, 108, 32, 136, 8
LTEXT """Programming Windows 95 with MFC""", -1, 108, 42, 136, 8
LTEXT "Copyright © 1996 by Jeff Prosise", -1, 108, 52, 136, 8
DEFPUSHBUTTON "OK", IDOK, 108, 72, 50, 14
END
LIFE.H
//***************************************************************************
//
// Life.h
//
//***************************************************************************
class CLifeApp : public CWinApp
{
public:
virtual BOOL InitInstance ();
protected:
afx_msg void OnAppAbout ();
DECLARE_MESSAGE_MAP ()
};
LIFE.CPP
//***************************************************************************
//
// Life.cpp
//
//***************************************************************************
#include <afxwin.h>
#include <afxext.h>
#include "Resource.h"
#include "Life.h"
#include "LifeDoc.h"
#include "MainFrm.h"
#include "LifeView.h"
#include "AboutDlg.h"
CLifeApp myApp;
BEGIN_MESSAGE_MAP (CLifeApp, CWinApp)
ON_COMMAND (ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND (ID_FILE_OPEN, CWinApp::OnFileOpen)
ON_COMMAND (ID_APP_ABOUT, OnAppAbout)
END_MESSAGE_MAP ()
BOOL CLifeApp::InitInstance ()
{
SetRegistryKey ("Microsoft Systems Journal");
LoadStdProfileSettings ();
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate (
IDR_MAINFRAME, // Resource ID
RUNTIME_CLASS (CLifeDoc), // Document class
RUNTIME_CLASS (CMainFrame), // Frame window class
RUNTIME_CLASS (CLifeView) // View class
);
AddDocTemplate (pDocTemplate);
EnableShellOpen ();
RegisterShellFileTypes ();
CCommandLineInfo cmdInfo;
ParseCommandLine (cmdInfo);
if (!ProcessShellCommand (cmdInfo))
return FALSE;
m_pMainWnd->DragAcceptFiles ();
return TRUE;
}
void CLifeApp::OnAppAbout ()
{
CAboutDialog dlg;
dlg.DoModal ();
}
MAINFRM.H
//***************************************************************************
//
// MainFrame.h
//
//***************************************************************************
class CMainFrame : public CFrameWnd
{
DECLARE_DYNCREATE (CMainFrame)
private:
CStatusBar m_wndStatusBar;
protected:
afx_msg int OnCreate (LPCREATESTRUCT);
DECLARE_MESSAGE_MAP ()
};
MAINFRM.CPP
//***************************************************************************
//
// MainFrame.cpp
//
//***************************************************************************
#include <afxwin.h>
#include <afxext.h>
#include "Resource.h"
#include "MainFrm.h"
IMPLEMENT_DYNCREATE (CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP (CMainFrame, CFrameWnd)
ON_WM_CREATE ()
END_MESSAGE_MAP ()
int CMainFrame::OnCreate (LPCREATESTRUCT lpcs)
{
if (CFrameWnd::OnCreate (lpcs) == -1)
return -1;
m_wndStatusBar.Create (this);
UINT nIndicator = ID_SEPARATOR;
m_wndStatusBar.SetIndicators (&nIndicator, 1);
return 0;
}
LIFEDOC.H
//***************************************************************************
//
// LifeDoc.h
//
//***************************************************************************
class CLifeDoc : public CDocument
{
DECLARE_DYNCREATE (CLifeDoc)
private:
int m_cx;
int m_cy;
BOOL m_bOpenEdge;
CByteArray m_byGrid;
CByteArray m_byBuffer;
void SetBackgroundCell (int, int, BOOL);
public:
CLifeDoc ();
virtual BOOL OnNewDocument ();
virtual void DeleteContents ();
virtual void Serialize (CArchive&);
CSize GetGridSize ();
BOOL GetCell (int, int);
BOOL ToggleCell (int, int);
int Evolve ();
protected:
afx_msg void OnOptionsStep ();
afx_msg void OnOptionsOpenBoundary ();
afx_msg void OnOptionsClosedBoundary ();
afx_msg void OnUpdateOptionsOpenBoundaryUI (CCmdUI*);
afx_msg void OnUpdateOptionsClosedBoundaryUI (CCmdUI*);
DECLARE_MESSAGE_MAP ()
};
LIFEDOC.CPP
//***************************************************************************
//
// LifeDoc.cpp
//
//***************************************************************************
#include <afxwin.h>
#include "Resource.h"
#include "LifeDoc.h"
#include "SizeDlg.h"
IMPLEMENT_DYNCREATE (CLifeDoc, CDocument)
BEGIN_MESSAGE_MAP (CLifeDoc, CDocument)
ON_COMMAND (ID_OPTIONS_STEP, OnOptionsStep)
ON_COMMAND (ID_OPTIONS_OPEN_BOUNDARY, OnOptionsOpenBoundary)
ON_COMMAND (ID_OPTIONS_CLOSED_BOUNDARY, OnOptionsClosedBoundary)
ON_UPDATE_COMMAND_UI (ID_OPTIONS_OPEN_BOUNDARY,
OnUpdateOptionsOpenBoundaryUI)
ON_UPDATE_COMMAND_UI (ID_OPTIONS_CLOSED_BOUNDARY,
OnUpdateOptionsClosedBoundaryUI)
END_MESSAGE_MAP ()
CLifeDoc::CLifeDoc ()
{
m_cx = -1;
m_cy = -1;
}
BOOL CLifeDoc::OnNewDocument ()
{
if (!CDocument::OnNewDocument ())
return FALSE;
if ((m_cx == -1) && (m_cy == -1)) {
m_cx = 24;
m_cy = 24;
}
else { // Prompt for grid size
CGridSizeDialog dlg;
dlg.m_cx = m_cx;
dlg.m_cy = m_cy;
dlg.DoModal ();
m_cx = dlg.m_cx;
m_cy = dlg.m_cy;
}
int nByteCount = ((m_cx * m_cy) + 7) / 8;
try { // Allocate grid memory
m_byGrid.SetSize (nByteCount);
m_byBuffer.SetSize (nByteCount);
}
catch (CMemoryException* e) { // Just in case...
e->Delete ();
return FALSE;
}
for (int i=0; i<nByteCount; i++) {
m_byGrid[i] = 0;
m_byBuffer[i] = 0;
}
return TRUE;
}
void CLifeDoc::DeleteContents ()
{
m_byGrid.RemoveAll ();
m_byBuffer.RemoveAll ();
}
void CLifeDoc::Serialize (CArchive& archive)
{
if (archive.IsStoring ())
archive << (WORD) m_cx << (WORD) m_cy;
else {
WORD cx, cy;
archive >> cx >> cy;
m_cx = (int) cx;
m_cy = (int) cy;
}
m_byGrid.Serialize (archive);
m_byBuffer.SetSize (m_byGrid.GetSize ());
}
void CLifeDoc::OnOptionsStep ()
{
Evolve ();
}
void CLifeDoc::OnOptionsOpenBoundary ()
{
m_bOpenEdge = TRUE;
}
void CLifeDoc::OnOptionsClosedBoundary ()
{
m_bOpenEdge = FALSE;
}
void CLifeDoc::OnUpdateOptionsOpenBoundaryUI (CCmdUI* pCmdUI)
{
pCmdUI->SetCheck (m_bOpenEdge ? 1 : 0);
}
void CLifeDoc::OnUpdateOptionsClosedBoundaryUI (CCmdUI* pCmdUI)
{
pCmdUI->SetCheck (m_bOpenEdge ? 0 : 1);
}
CSize CLifeDoc::GetGridSize ()
{
return CSize (m_cx, m_cy);
}
BOOL CLifeDoc::GetCell (int nRow, int nCol)
{
if ((nRow < 0) || (nRow >= m_cy) ||
(nCol < 0) || (nCol >= m_cx))
return FALSE;
int nBitNumber = ((nRow * m_cx) + nCol) % 8;
int nByteNumber = ((nRow * m_cx) + nCol) / 8;
return m_byGrid[nByteNumber] & (1 << nBitNumber);
}
BOOL CLifeDoc::ToggleCell (int nRow, int nCol)
{
if ((nRow < 0) || (nRow >= m_cy) ||
(nCol < 0) || (nCol >= m_cx))
return FALSE;
int nBitNumber = ((nRow * m_cx) + nCol) % 8;
int nByteNumber = ((nRow * m_cx) + nCol) / 8;
m_byGrid[nByteNumber] ^= (1 << nBitNumber);
SetModifiedFlag ();
return m_byGrid[nByteNumber] & (1 << nBitNumber);
}
int CLifeDoc::Evolve ()
{
int nPrevRow, nPrevCol;
int nNextRow, nNextCol;
int nNeighbors, i, j;
int nLiveCells = 0;
BOOL bAlive;
for (i=0; i<m_cy; i++) { // Do rows on the outside loop...
if (m_bOpenEdge) {
nPrevRow = (i == 0) ? m_cy - 1 : i - 1;
nNextRow = (i == (m_cy - 1)) ? 0 : i + 1;
}
else {
nPrevRow = (i == 0) ? -1 : i - 1;
nNextRow = (i == (m_cy - 1)) ? -1 : i + 1;
}
for (j=0; j<m_cx; j++) { // ...and columns on the inside
if (m_bOpenEdge) {
nPrevCol = (j == 0) ? m_cx - 1 : j - 1;
nNextCol = (j == (m_cx - 1)) ? 0 : j + 1;
}
else {
nPrevCol = (j == 0) ? -1 : j - 1;
nNextCol = (j == (m_cx - 1)) ? -1 : j + 1;
}
nNeighbors = 0;
if (GetCell (nPrevRow, nPrevCol))
nNeighbors++;
if (GetCell (nPrevRow, j))
nNeighbors++;
if (GetCell (nPrevRow, nNextCol))
nNeighbors++;
if (GetCell (i, nPrevCol))
nNeighbors++;
if (GetCell (i, nNextCol))
nNeighbors++;
if (GetCell (nNextRow, nPrevCol))
nNeighbors++;
if (GetCell (nNextRow, j))
nNeighbors++;
if (GetCell (nNextRow, nNextCol))
nNeighbors++;
bAlive = GetCell (i, j);
if ((bAlive && ((nNeighbors == 2) ||
(nNeighbors == 3))) || (!bAlive && (nNeighbors == 3))) {
SetBackgroundCell (i, j, TRUE);
nLiveCells++;
}
else
SetBackgroundCell (i, j, FALSE);
}
}
int nByteCount = ((m_cx * m_cy) + 7) / 8;
for (i=0; i<nByteCount; i++)
m_byGrid[i] = m_byBuffer[i];
SetModifiedFlag ();
UpdateAllViews (NULL, 1);
return nLiveCells;
}
void CLifeDoc::SetBackgroundCell (int nRow, int nCol, BOOL bState)
{
int nBitNumber = ((nRow * m_cx) + nCol) % 8;
int nByteNumber = ((nRow * m_cx) + nCol) / 8;
if (bState)
m_byBuffer[nByteNumber] |= (1 << nBitNumber);
else
m_byBuffer[nByteNumber] &= ~(1 << nBitNumber);
}
LIFEVIEW.H
//***************************************************************************
//
// LifeView.h
//
//***************************************************************************
class CLifeView : public CScrollView
{
DECLARE_DYNCREATE (CLifeView)
private:
int m_nPrevRow;
int m_nPrevCol;
CBitmap m_bmGrayCell;
CBitmap m_bmBlueCell;
CPoint m_ptOrg;
void DrawCell (CDC*, int, int, BOOL);
void SetGridOrigin (int, int);
void SetScrollParms ();
public:
CLifeView ();
CLifeDoc* GetDocument ();
virtual void OnInitialUpdate ();
protected:
virtual void OnDraw (CDC*);
virtual void OnUpdate (CView*, LPARAM, CObject*);
afx_msg void OnSize (UINT, int, int);
afx_msg BOOL OnEraseBkgnd (CDC*);
afx_msg void OnLButtonDown (UINT, CPoint);
afx_msg void OnMouseMove (UINT, CPoint);
DECLARE_MESSAGE_MAP ()
};
LIFEVIEW.CPP
//***************************************************************************
//
// LifeView.cpp
//
//***************************************************************************
#include <afxwin.h>
#include <afxext.h>
#include "Resource.h"
#include "MainFrm.h"
#include "LifeDoc.h"
#include "LifeView.h"
IMPLEMENT_DYNCREATE (CLifeView, CScrollView)
BEGIN_MESSAGE_MAP (CLifeView, CScrollView)
ON_WM_SIZE ()
ON_WM_ERASEBKGND ()
ON_WM_LBUTTONDOWN ()
ON_WM_MOUSEMOVE ()
END_MESSAGE_MAP ()
CLifeView::CLifeView ()
{
m_bmGrayCell.LoadBitmap ("GrayCell");
m_bmBlueCell.LoadBitmap ("BlueCell");
}
void CLifeView::OnInitialUpdate ()
{
m_nPrevRow = -1;
m_nPrevCol = -1;
SetScrollParms ();
CRect rect;
GetClientRect (&rect);
SetGridOrigin (rect.Width (), rect.Height ());
CScrollView::OnInitialUpdate ();
}
void CLifeView::OnUpdate (CView* pSender, LPARAM lHint, CObject* pHint)
{
Invalidate (lHint ? FALSE : TRUE);
}
void CLifeView::OnSize (UINT nType, int cx, int cy)
{
CScrollView::OnSize (nType, cx, cy);
SetGridOrigin (cx, cy);
}
BOOL CLifeView::OnEraseBkgnd (CDC* pDC)
{
CRect rect;
GetClientRect (&rect);
CBrush brush ((COLORREF) ::GetSysColor (COLOR_APPWORKSPACE));
pDC->FillRect (rect, &brush);
return TRUE;
}
void CLifeView::OnDraw (CDC* pDC)
{
CLifeDoc* pDoc = GetDocument ();
CSize size = pDoc->GetGridSize ();
CDC mdcGray, mdcBlue;
mdcGray.CreateCompatibleDC (pDC);
mdcBlue.CreateCompatibleDC (pDC);
CBitmap* pOldGrayBitmap = mdcGray.SelectObject (&m_bmGrayCell);
CBitmap* pOldBlueBitmap = mdcBlue.SelectObject (&m_bmBlueCell);
CRect rect;
rect = ((CPaintDC*) pDC)->m_ps.rcPaint;
pDC->DPtoLP (&rect);
int x1, y1, x2, y2;
x1 = max (0, (rect.left - m_ptOrg.x) / CELLWIDTH);
y1 = max (0, (rect.top - m_ptOrg.y) / CELLHEIGHT);
x2 = min (size.cx, ((rect.right - m_ptOrg.x) / CELLWIDTH) + 1);
y2 = min (size.cy, ((rect.bottom - m_ptOrg.y) / CELLHEIGHT) + 1);
int i, j;
for (i=y1; i<y2; i++)
for (j=x1; j<x2; j++)
pDC->BitBlt (m_ptOrg.x + (j * CELLWIDTH),
m_ptOrg.y + (i * CELLHEIGHT), CELLWIDTH, CELLHEIGHT,
pDoc->GetCell (i, j) ? &mdcBlue : &mdcGray, 0, 0, SRCCOPY);
mdcBlue.SelectObject (pOldBlueBitmap);
mdcGray.SelectObject (pOldGrayBitmap);
}
void CLifeView::OnLButtonDown (UINT nFlags, CPoint point)
{
CLifeDoc* pDoc = GetDocument ();
CSize size = pDoc->GetGridSize ();
if ((point.x < m_ptOrg.x) ||
(point.x > (m_ptOrg.x + (size.cx * CELLWIDTH))) ||
(point.y < m_ptOrg.y) ||
(point.y > (m_ptOrg.y + (size.cy * CELLHEIGHT))))
return;
point.x -= m_ptOrg.x;
point.y -= m_ptOrg.y;
CClientDC dc (this);
OnPrepareDC (&dc);
dc.DPtoLP (&point);
int nRow = point.y / CELLHEIGHT;
int nCol = point.x / CELLWIDTH;
m_nPrevRow = nRow;
m_nPrevCol = nCol;
BOOL bState = pDoc->ToggleCell (nRow, nCol);
DrawCell (&dc, nRow, nCol, bState);
}
void CLifeView::OnMouseMove (UINT nFlags, CPoint point)
{
if (!(nFlags & MK_LBUTTON))
return;
CLifeDoc* pDoc = GetDocument ();
CSize size = pDoc->GetGridSize ();
if ((point.x < m_ptOrg.x) ||
(point.x > (m_ptOrg.x + (size.cx * CELLWIDTH))) ||
(point.y < m_ptOrg.y) ||
(point.y > (m_ptOrg.y + (size.cy * CELLHEIGHT))))
return;
point.x -= m_ptOrg.x;
point.y -= m_ptOrg.y;
CClientDC dc (this);
OnPrepareDC (&dc);
dc.DPtoLP (&point);
int nRow = point.y / CELLHEIGHT;
int nCol = point.x / CELLWIDTH;
if ((nRow == m_nPrevRow) && (nCol == m_nPrevCol))
return;
m_nPrevRow = nRow;
m_nPrevCol = nCol;
BOOL bState = pDoc->ToggleCell (nRow, nCol);
DrawCell (&dc, nRow, nCol, bState);
}
void CLifeView::DrawCell (CDC* pDC, int nRow, int nCol, BOOL bState)
{
CDC mdc;
mdc.CreateCompatibleDC (pDC);
CBitmap* pOldBitmap = mdc.SelectObject (bState ?
&m_bmBlueCell : &m_bmGrayCell);
pDC->BitBlt (m_ptOrg.x + (nCol * CELLWIDTH),
m_ptOrg.y + (nRow * CELLHEIGHT), CELLWIDTH, CELLHEIGHT, &mdc,
0, 0, SRCCOPY);
mdc.SelectObject (pOldBitmap);
}
void CLifeView::SetGridOrigin (int cx, int cy)
{
m_ptOrg.x = m_ptOrg.y = 0;
CSize size = GetDocument ()->GetGridSize ();
if (cx > (size.cx * CELLWIDTH))
m_ptOrg.x = (cx - (size.cx * CELLWIDTH)) / 2;
if (cy > (size.cy * CELLHEIGHT))
m_ptOrg.y = (cy - (size.cy * CELLHEIGHT)) / 2;
}
void CLifeView::SetScrollParms ()
{
CSize sizeTotal = GetDocument ()->GetGridSize ();
sizeTotal.cx *= CELLWIDTH;
sizeTotal.cy *= CELLHEIGHT;
CSize sizePage (CELLWIDTH * 10, CELLHEIGHT * 10);
CSize sizeLine (CELLWIDTH, CELLHEIGHT);
SetScrollSizes (MM_TEXT, sizeTotal, sizePage, sizeLine);
}
CLifeDoc* CLifeView::GetDocument ()
{
return (CLifeDoc*) m_pDocument;
}
SIZEDLG.H
//***************************************************************************
//
// SizeDlg.h
//
//***************************************************************************
class CGridSizeDialog : public CDialog
{
public:
int m_cx;
int m_cy;
CGridSizeDialog (CWnd* pParentWnd = NULL) :
CDialog ("GridSize", pParentWnd) {}
protected:
virtual BOOL OnInitDialog ();
virtual void OnCancel ();
virtual void DoDataExchange (CDataExchange*);
};
SIZEDLG.CPP
//***************************************************************************
//
// SizeDlg.cpp
//
//***************************************************************************
#include <afxwin.h>
#include "Resource.h"
#include "SizeDlg.h"
BOOL CGridSizeDialog::OnInitDialog ()
{
CDialog::OnInitDialog ();
CEdit* pEditHorz = (CEdit*) GetDlgItem (IDC_HORZ);
CEdit* pEditVert = (CEdit*) GetDlgItem (IDC_VERT);
pEditHorz->LimitText (4);
pEditVert->LimitText (4);
CenterWindow ();
return TRUE;
}
void CGridSizeDialog::OnCancel ()
{
// Do nothing so the dialog box will not be destroyed
}
void CGridSizeDialog::DoDataExchange (CDataExchange* pDX)
{
CDialog::DoDataExchange (pDX);
DDX_Text (pDX, IDC_HORZ, m_cx);
DDV_MinMaxInt (pDX, m_cx, 8, 512);
DDX_Text (pDX, IDC_VERT, m_cy);
DDV_MinMaxInt (pDX, m_cy, 8, 512);
}
ABOUTDLG.H
//***************************************************************************
//
// AboutDlg.h
//
//***************************************************************************
class CAboutDialog : public CDialog
{
private:
CRect m_rect;
public:
CAboutDialog (CWnd* pParentWnd = NULL) :
CDialog ("About", pParentWnd) {}
protected:
virtual BOOL OnInitDialog ();
afx_msg void OnPaint ();
DECLARE_MESSAGE_MAP ()
};
ABOUTDLG.CPP
//***************************************************************************
//
// AboutDlg.cpp
//
//***************************************************************************
#include <afxwin.h>
#include "Resource.h"
#include "AboutDlg.h"
BEGIN_MESSAGE_MAP (CAboutDialog, CDialog)
ON_WM_PAINT ()
END_MESSAGE_MAP ()
BOOL CAboutDialog::OnInitDialog ()
{
CDialog::OnInitDialog ();
CStatic* pStatic = (CStatic*) GetDlgItem (IDC_ICONRECT);
pStatic->GetWindowRect (&m_rect);
pStatic->DestroyWindow ();
ScreenToClient (&m_rect);
CenterWindow ();
return TRUE;
}
void CAboutDialog::OnPaint ()
{
CPaintDC dc (this);
HICON hIcon = (HICON) ::GetClassLong (AfxGetMainWnd ()->m_hWnd,
GCL_HICON);
if (hIcon != NULL) {
CDC mdc;
mdc.CreateCompatibleDC (&dc);
CBrush brush;
brush.CreateStockObject (LTGRAY_BRUSH);
CBitmap bitmap;
bitmap.CreateCompatibleBitmap (&dc, 32, 32);
CBitmap* pOldBitmap = mdc.SelectObject (&bitmap);
CRect rcIcon (0, 0, 32, 32);
mdc.FillRect (&rcIcon, &brush);
mdc.DrawIcon (0, 0, hIcon);
dc.StretchBlt (m_rect.left, m_rect.top, m_rect.Width(),
m_rect.Height (), &mdc, 0, 0, 32, 32, SRCCOPY);
mdc.SelectObject (pOldBitmap);
}
}