Figure 4 Simplified DOCOBJ.H
//----------------------------------------------------------------------------
// OLE Document Object interfaces
// Copyright 1995 - 1996 Microsoft Corporation. All Rights Reserved.
//----------------------------------------------------------------------------
interface IOleDocument;
interface IOleDocumentSite;
interface IOleDocumentView;
interface IEnumOleDocumentViews;
interface IContinueCallback;
interface IPrint;
interface IOleCommandTarget;
interface IOleDocument : IUnknown
{
typedef [unique] IOleDocument *LPOLEDOCUMENT;
typedef enum {
DOCMISC_CANCREATEMULTIPLEVIEWS = 1,
DOCMISC_SUPPORTCOMPLEXRECTANGLES = 2,
DOCMISC_CANTOPENEDIT = 4, // fails the
// IOleDocumentView::Open method
DOCMISC_NOFILESUPPORT = 8, // does not support read/
// writing to a file
} DOCMISC;
HRESULT CreateView(
[in, unique] IOleInPlaceSite *pIPSite,
[in, unique] IStream *pstm,
[in] DWORD dwReserved,
[out] IOleDocumentView **ppView);
HRESULT GetDocMiscStatus(
[out] DWORD *pdwStatus);
HRESULT EnumViews(
[out] IEnumOleDocumentViews **ppEnum,
[out] IOleDocumentView **ppView);
}
//---------------------------------------------------------------------------
interface IOleDocumentSite : IUnknown
{
typedef [unique] IOleDocumentSite *LPOLEDOCUMENTSITE;
HRESULT ActivateMe(
[in] IOleDocumentView *pViewToActivate);
}
//----------------------------------------------------------------------------
interface IOleDocumentView : IUnknown
{
typedef [unique] IOleDocumentView *LPOLEDOCUMENTVIEW;
HRESULT SetInPlaceSite(
[in, unique] IOleInPlaceSite *pIPSite);
HRESULT GetInPlaceSite(
[out] IOleInPlaceSite **ppIPSite);
HRESULT GetDocument(
[out] IUnknown **ppunk);
[input_sync]
HRESULT SetRect(
[in] LPRECT prcView);
HRESULT GetRect(
[out] LPRECT prcView);
[input_sync]
HRESULT SetRectComplex(
[in, unique] LPRECT prcView,
[in, unique] LPRECT prcHScroll,
[in, unique] LPRECT prcVScroll,
[in, unique] LPRECT prcSizeBox);
HRESULT Show(
[in] BOOL fShow);
HRESULT UIActivate(
[in] BOOL fUIActivate);
HRESULT Open(void);
HRESULT CloseView(DWORD dwReserved);
HRESULT SaveViewState(
[in] LPSTREAM pstm);
HRESULT ApplyViewState(
[in] LPSTREAM pstm);
HRESULT Clone(
[in] IOleInPlaceSite *pIPSiteNew,
[out] IOleDocumentView **ppViewNew);
}
//----------------------------------------------------------------------------
interface IEnumOleDocumentViews : IUnknown
{
typedef [unique] IEnumOleDocumentViews *LPENUMOLEDOCUMENTVIEWS;
[local]
HRESULT __stdcall Next(
[in] ULONG cViews,
[out] IOleDocumentView **rgpView,
[out] ULONG *pcFetched);
[call_as(Next)]
HRESULT __stdcall RemoteNext(
[in] ULONG cViews,
[out, size_is(cViews), length_is(*pcFetched)]
IOleDocumentView **rgpView,
[out] ULONG *pcFetched);
HRESULT Skip(
[in] ULONG cViews);
HRESULT Reset();
HRESULT Clone(
[out] IEnumOleDocumentViews **ppEnum);
}
//----------------------------------------------------------------------------
interface IContinueCallback : IUnknown
{
typedef [unique] IContinueCallback *LPCONTINUECALLBACK;
HRESULT FContinue();
HRESULT FContinuePrinting(
[in] LONG nCntPrinted,
[in] LONG nCurPage,
[in, unique] wchar_t * pwszPrintStatus);
}
//----------------------------------------------------------------------------
interface IPrint : IUnknown
{
typedef [unique] IPrint *LPPRINT;
typedef enum
{
PRINTFLAG_MAYBOTHERUSER = 1,
PRINTFLAG_PROMPTUSER = 2,
PRINTFLAG_USERMAYCHANGEPRINTER = 4,
PRINTFLAG_RECOMPOSETODEVICE = 8,
PRINTFLAG_DONTACTUALLYPRINT = 16,
PRINTFLAG_FORCEPROPERTIES = 32,
PRINTFLAG_PRINTTOFILE = 64
} PRINTFLAG;
typedef struct tagPAGERANGE
{
LONG nFromPage;
LONG nToPage;
} PAGERANGE;
typedef struct tagPAGESET
{
ULONG cbStruct;
BOOL fOddPages;
BOOL fEvenPages;
ULONG cPageRange;
[size_is(cPageRange)]
PAGERANGE rgPages[];
} PAGESET;
cpp_quote("#define PAGESET_TOLASTPAGE ((WORD)(-1L))")
HRESULT SetInitialPageNum(
[in] LONG nFirstPage);
HRESULT GetPageInfo(
[out] LONG *pnFirstPage,
[out] LONG *pcPages);
[local]
HRESULT __stdcall Print(
[in] DWORD grfFlags,
[in, out] DVTARGETDEVICE **pptd,
[in, out] PAGESET ** ppPageSet,
[in, out, unique] STGMEDIUM * pstgmOptions,
[in] IContinueCallback *pcallback,
[in] LONG nFirstPage,
[out] LONG *pcPagesPrinted,
[out] LONG *pnLastPage);
[call_as(Print)]
HRESULT __stdcall RemotePrint(
[in] DWORD grfFlags,
[in, out] DVTARGETDEVICE **pptd,
[in, out] PAGESET ** pppageset,
[in, out, unique] RemSTGMEDIUM * pstgmOptions,
[in] IContinueCallback * pcallback,
[in] LONG nFirstPage,
[out] LONG * pcPagesPrinted,
[out] LONG * pnLastPage);
}
//----------------------------------------------------------------------------
interface IOleCommandTarget : IUnknown
{
typedef [unique] IOleCommandTarget *LPOLECOMMANDTARGET;
typedef enum
{
OLECMDF_SUPPORTED = 0x00000001,
OLECMDF_ENABLED = 0x00000002,
OLECMDF_LATCHED = 0x00000004,
OLECMDF_NINCHED = 0x00000008,
} OLECMDF;
typedef struct _tagOLECMD {
ULONG cmdID;
DWORD cmdf;
} OLECMD;
typedef struct _tagOLECMDTEXT{
DWORD cmdtextf;
ULONG cwActual;
ULONG cwBuf; /* size in wide chars of the buffer for text */
[size_is(cwBuf)]
wchar_t rgwz[]; /* Array into which callee writes the text */
} OLECMDTEXT;
typedef enum
{
OLECMDTEXTF_NONE = 0,
OLECMDTEXTF_NAME = 1,
OLECMDTEXTF_STATUS = 2,
} OLECMDTEXTF;
typedef enum
{
OLECMDEXECOPT_DODEFAULT = 0,
OLECMDEXECOPT_PROMPTUSER = 1,
OLECMDEXECOPT_DONTPROMPTUSER = 2,
OLECMDEXECOPT_SHOWHELP = 3
} OLECMDEXECOPT;
typedef enum {
OLECMDID_OPEN = 1,
OLECMDID_NEW = 2,
OLECMDID_SAVE = 3,
OLECMDID_SAVEAS = 4,
OLECMDID_SAVECOPYAS = 5,
OLECMDID_PRINT = 6,
OLECMDID_PRINTPREVIEW = 7,
OLECMDID_PAGESETUP = 8,
OLECMDID_SPELL = 9,
OLECMDID_PROPERTIES = 10,
OLECMDID_CUT = 11,
OLECMDID_COPY = 12,
OLECMDID_PASTE = 13,
OLECMDID_PASTESPECIAL = 14,
OLECMDID_UNDO = 15,
OLECMDID_REDO = 16,
OLECMDID_SELECTALL = 17,
OLECMDID_CLEARSELECTION = 18,
OLECMDID_ZOOM = 19,
OLECMDID_GETZOOMRANGE = 20
} OLECMDID;
//----------------------------------------------------------------------------
// error codes
#define OLECMDERR_E_FIRST (OLE_E_LAST+1)
#define OLECMDERR_E_NOTSUPPORTED (OLECMDERR_E_FIRST)
#define OLECMDERR_E_DISABLED (OLECMDERR_E_FIRST+1)
#define OLECMDERR_E_NOHELP (OLECMDERR_E_FIRST+2)
#define OLECMDERR_E_CANCELED (OLECMDERR_E_FIRST+3)
#define OLECMDERR_E_UNKNOWNGROUP (OLECMDERR_E_FIRST+4)
[input_sync]
HRESULT QueryStatus(
[in, unique] const GUID *pguidCmdGroup,
[in] ULONG cCmds,
[size_is(cCmds)]
[in, out] OLECMD prgCmds[],
[in, out, unique] OLECMDTEXT *pCmdText);
HRESULT Exec(
[in, unique] const GUID *pguidCmdGroup,
[in] DWORD nCmdID,
[in] DWORD nCmdexecopt,
[in, unique] VARIANTARG *pvaIn,
[in, out, unique] VARIANTARG *pvaOut);
}
Figure 5 IOleDocumentView Functions
SetInPlaceSite | Associates a view site object (provided by the container) with this view. |
GetInPlaceSite | Returns a pointer to this view's associated site. |
GetDocument | Returns a pointer to this view's associated document. |
SetRect | Sets the viewpoint coordinates for this view. |
GetRect | Retrieves the viewpoint coordinates for this view. |
SetRectComplex | Lets the container specify not only the simple view rectangle but also the area occupied by the view's scrollbars and sizing box. (Complex rectangles don't have to be supported by a view; the container can find this out through the IOleDocument::GetMiscStatus function, which will include the DOCMISC_SUPPORTCOMPLEXRECTANGLES flag on return if this support exists.) |
Show | Indicates whether to show or hide this view. |
UIActivate | Indicates whether to UI activate or deactivate this view. |
Open | Asks to display the view in a separate window. (This ability can be turned off with the DOCMISC_CANTOPENEDIT MiscStatus bit.) |
CloseView | Asks this view to shut itself down. |
SaveViewState | Writes the view's state information to an IStream. |
ApplyViewState | Asks a view to restore its state to a previously saved setting in an IStream. |
Clone | Asks this view to duplicate itself with the same view context, but in a different viewport. |
Figure 6 OLECMD Flags
Flag | Description |
OLECMDF_SUPPORTED | The command is supported by this object. |
OLECMDF_ENABLED | The command is available and enabled. |
OLECMDF_LATCHED | The command is an on-off toggle and is currently on. |
OLECMDF_NINCHED | The command is an on-off toggle but the state cannot be determined because the attribute of this command is found in both on and off states in the relevant selection. This state corresponds to an "indeterminate" state of a 3-state checkbox, for example. |
Figure 7 OLECMDEXECOPT Options
Flag | Description |
OLECMDEXECOPT_PROMPTUSER | Execute the command after taking user input. |
OLECMDEXECOPT_DONTPROMPTUSER | Execute the command without prompting the user (for example, clicking on the Print toolbar button causes the document to be immediately printed without requir-ing user input). |
OLECMDEXECOPT_DODEFAULT | Caller is not sure whether the user should be prompted or not. |
OLECMDEXECOPT_SHOWHELP | Object should show help for the corre-sponding command and not execute. |
Figure 8 IOleCommandTarget Commands for Exec
Identifier | Description |
OLECMDID_OPEN | File Open |
OLECMDID_NEW | File New |
OLECMDID_SAVE | File Save |
OLECMDID_SAVEAS | File Save As |
OLECMDID_SAVECOPYAS | File Save Copy As |
OLECMDID_PRINT | File Print |
OLECMDID_PRINTPREVIEW | File Print Preview |
OLECMDID_PAGESETUP | File Page Setup |
OLECMDID_SPELL | Tools Spelling |
OLECMDID_PROPERTIES | File Properties |
OLECMDID_CUT | Edit Cut |
OLECMDID_COPY | Edit Copy |
OLECMDID_PASTE | Edit Paste |
OLECMDID_PASTESPECIAL | Edit Paste Special |
OLECMDID_UNDO | Edit Undo |
OLECMDID_REDO | Edit Redo |
OLECMDID_SELECTALL | Edit Select All |
OLECMDID_CLEARSELECTION | Edit Clear |
OLECMDID_ZOOM | Query zoom value / display zoom dialog / set zoom value |
OLECMDID_GETZOOMRANGE | Retrieves zoom range applicable to View Zoom |
Figure 9 IPrint::Print Flags
Value | Description |
PRINTFLAG_MAYBOTHERUSER* | Specifies that user interaction is permitted. If not set, the printing process must not require any user input. |
PRINTFLAG_PROMPTUSER | Prompt the user for job-specific printing options using the normal print dialog for the object. Support for this option is required. (PRINTFLAG_MAYBOTHERUSER must, of course, be specified as well.) |
PRINTFLAG_USERMAYCHANGEPRINTER | The user may change the target printer. (Again, this is only valid if PRINTFLAG_ |
PROMPTUSER is also specified.) | |
PRINTFLAG_RECOMPOSETODEVICE | The print job should recompose itself for the indicated target device. Otherwise, it should attempt to use its existing compositional-device association. |
PRINTFLAG_DONTACTUALLYPRINT | Do a printing dry run, with any prompting as indicated but without actually sending a print job. |
PRINTFLAG_PRINTTOFILE | Print to a file. (The portname field of DVTARGETDEVICE, an argument to the in on the Print function, should indicate the filename.) |
* Indicates that this identifier name has replaced the DoughnutHoleSize property in Microsoft Excel as the author's favorite. |
Figure 10 Changes in Scribble
Ipframe.h
// ipframe.h : interface of the CInPlaceFrame class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
class CInPlaceFrame : public CDocObjectIPFrameWnd
{
DECLARE_DYNCREATE(CInPlaceFrame)
public:
CInPlaceFrame();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CInPlaceFrame)
public:
virtual BOOL OnCreateControlBars(CFrameWnd* pWndFrame, CFrameWnd* pWndDoc);
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CInPlaceFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
CToolBar m_wndToolBar;
COleResizeBar m_wndResizeBar;
COleDropTarget m_dropTarget;
// Generated message map functions
protected:
//{{AFX_MSG(CInPlaceFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
Ipframe.cpp
// ipframe.cpp : implementation of the CInPlaceFrame class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "scribble.h"
#include "ipframe.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
//BINDER:
// An MFC application's in-place frame window is normally a subclass
// of COleIPFrameWnd. To be Binder-compatible, we steal code from
// CDocObjectIPFrameWnd instead.
//BINDER_END
/////////////////////////////////////////////////////////////////////////////
// CInPlaceFrame
IMPLEMENT_DYNCREATE(CInPlaceFrame, CDocObjectIPFrameWnd)
BEGIN_MESSAGE_MAP(CInPlaceFrame, CDocObjectIPFrameWnd)
//{{AFX_MSG_MAP(CInPlaceFrame)
ON_WM_CREATE()
//}}AFX_MSG_MAP
// Global help commands
ON_COMMAND(ID_HELP_INDEX, CDocObjectIPFrameWnd::OnHelpIndex)
ON_COMMAND(ID_HELP_USING, CDocObjectIPFrameWnd::OnHelpUsing)
ON_COMMAND(ID_HELP, CDocObjectIPFrameWnd::OnHelp)
ON_COMMAND(ID_DEFAULT_HELP, CDocObjectIPFrameWnd::OnHelpIndex)
ON_COMMAND(ID_CONTEXT_HELP, CDocObjectIPFrameWnd::OnContextHelp)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// arrays of IDs used to initialize control bars
// toolbar buttons - IDs are command buttons
static UINT BASED_CODE buttons[] =
{
// same order as in the bitmap 'itoolbar.bmp'
ID_EDIT_CUT,
ID_EDIT_COPY,
ID_EDIT_PASTE,
ID_SEPARATOR,
ID_PEN_THICK_OR_THIN,
ID_SEPARATOR,
ID_APP_ABOUT,
ID_CONTEXT_HELP,
};
/////////////////////////////////////////////////////////////////////////////
// CInPlaceFrame construction/destruction
CInPlaceFrame::CInPlaceFrame()
{
}
CInPlaceFrame::~CInPlaceFrame()
{
}
int CInPlaceFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDocObjectIPFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// CResizeBar implements in-place resizing.
if (!m_wndResizeBar.Create(this))
{
TRACE0("Failed to create resize bar\n");
return -1; // fail to create
}
// By default, it is a good idea to register a drop-target that does
// nothing with your frame window. This prevents drops from
// "falling through" to a container that supports drag-drop.
m_dropTarget.Register(this);
return 0;
}
// OnCreateControlBars is called by the framework to create control bars on the
// container application's windows. pWndFrame is the top level frame window of
// the container and is always non-NULL. pWndDoc is the doc level frame window
// and will be NULL when the container is an SDI application. A server
// application can place MFC control bars on either window.
BOOL CInPlaceFrame::OnCreateControlBars(CFrameWnd* pWndFrame,
CFrameWnd* pWndDoc)
{
// Create toolbar on client's frame window
if (!m_wndToolBar.Create(pWndFrame) ||
!m_wndToolBar.LoadBitmap(IDR_SCRIBTYPE_SRVR_IP) ||
!m_wndToolBar.SetButtons(buttons, sizeof(buttons)/sizeof(UINT)))
{
TRACE0("Failed to create toolbar\n");
return FALSE;
}
// Set owner to this window, so messages are delivered to correct app
m_wndToolBar.SetOwner(this);
// TODO: Delete these three lines if you don't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
pWndFrame->EnableDocking(CBRS_ALIGN_ANY);
pWndFrame->DockControlBar(&m_wndToolBar);
// TODO: Remove this if you don't want tool tips
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY);
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CInPlaceFrame diagnostics
#ifdef _DEBUG
void CInPlaceFrame::AssertValid() const
{
CDocObjectIPFrameWnd::AssertValid();
}
void CInPlaceFrame::Dump(CDumpContext& dc) const
{
CDocObjectIPFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CInPlaceFrame commands
Scribdoc.h
// scribdoc.h : interface of the CScribDoc class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
//
// Forward declaration of data structure class
class CStroke;
class CScribItem;
class CScribDoc : public CDocObjectServerDoc
{
protected: // create from serialization only
CScribDoc();
DECLARE_DYNCREATE(CScribDoc)
// Attributes
protected:
// The document keeps track of the current pen width on
// behalf of all views. We'd like the user interface of
// Scribble to be such that if the user chooses the Draw
// Thick Line command, it will apply to all views, not just
// the view that currently has the focus.
UINT m_nPenWidth; // current user-selected pen width
BOOL m_bThickPen; // TRUE if current pen is thick
UINT m_nThinWidth;
UINT m_nThickWidth;
CPen m_penCur; // pen created according to
// user-selected pen style (width)
public:
CTypedPtrList<CObList,CStroke*> m_strokeList;
CPen* GetCurrentPen() { return &m_penCur; }
protected:
CSize m_sizeDoc;
public:
CSize GetDocSize() { return m_sizeDoc; }
COleServerItem* OnGetEmbeddedItem();
CScribItem* GetEmbeddedItem()
{ return (CScribItem*)COleServerDoc::GetEmbeddedItem(); }
// Operations
public:
CStroke* NewStroke();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CScribDoc)
public:
virtual BOOL OnNewDocument();
virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
virtual void DeleteContents();
//}}AFX_VIRTUAL
// Implementation
protected:
void ReplacePen();
void OnSetItemRects(LPCRECT lpPosRect, LPCRECT lpClipRect);
public:
virtual ~CScribDoc();
virtual void Serialize(CArchive& ar); // overridden for document i/o
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
void InitDocument();
// Generated message map functions
protected:
//{{AFX_MSG(CScribDoc)
afx_msg void OnEditClearAll();
afx_msg void OnPenThickOrThin();
afx_msg void OnUpdateEditClearAll(CCmdUI* pCmdUI);
afx_msg void OnUpdatePenThickOrThin(CCmdUI* pCmdUI);
afx_msg void OnPenWidths();
afx_msg void OnEditCopy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// class CStroke
//
// A stroke is a series of connected points in the scribble drawing.
// A scribble document may have multiple strokes.
class CStroke : public CObject
{
public:
CStroke(UINT nPenWidth);
protected:
CStroke();
DECLARE_SERIAL(CStroke)
// Attributes
UINT m_nPenWidth; // one pen width applies to entire
// stroke
CArray<CPoint,CPoint> m_pointArray; // series of connected points
CRect m_rectBounding; // smallest rect that surrounds all
// of the points in the stroke
// measured in MM_LOENGLISH units
// (0.01 inches, with Y-axis inverted)
public:
CRect& GetBoundingRect() { return m_rectBounding; }
// Operations
public:
BOOL DrawStroke(CDC* pDC);
void FinishStroke();
public:
virtual void Serialize(CArchive& ar);
};
Scribdoc.cpp
// scribdoc.cpp : implementation of the CScribDoc class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
//
#include "stdafx.h"
#include "scribble.h"
#include "scribdoc.h"
#include "pendlg.h"
#include "scribvw.h"
#include "scribitm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScribDoc
IMPLEMENT_DYNCREATE(CScribDoc, CDocObjectServerDoc)
BEGIN_MESSAGE_MAP(CScribDoc, CDocObjectServerDoc)
//{{AFX_MSG_MAP(CScribDoc)
ON_COMMAND(ID_EDIT_CLEAR_ALL, OnEditClearAll)
ON_COMMAND(ID_PEN_THICK_OR_THIN, OnPenThickOrThin)
ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR_ALL, OnUpdateEditClearAll)
ON_UPDATE_COMMAND_UI(ID_PEN_THICK_OR_THIN, OnUpdatePenThickOrThin)
ON_COMMAND(ID_PEN_WIDTHS, OnPenWidths)
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScribDoc construction/destruction
CScribDoc::CScribDoc()
{
m_sizeDoc = CSize(200, 200);
}
CScribDoc::~CScribDoc()
{
}
BOOL CScribDoc::OnNewDocument()
{
if (!CDocObjectServerDoc::OnNewDocument())
return FALSE;
InitDocument();
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CScribDoc serialization
void CScribDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_sizeDoc;
}
else
{
ar >> m_sizeDoc;
}
m_strokeList.Serialize(ar);
}
/////////////////////////////////////////////////////////////////////////////
// CScribDoc diagnostics
#ifdef _DEBUG
void CScribDoc::AssertValid() const
{
CDocObjectServerDoc::AssertValid();
}
void CScribDoc::Dump(CDumpContext& dc) const
{
CDocObjectServerDoc::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CScribDoc commands
BOOL CScribDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocObjectServerDoc::OnOpenDocument(lpszPathName))
return FALSE;
InitDocument();
return TRUE;
}
void CScribDoc::DeleteContents()
{
while (!m_strokeList.IsEmpty())
{
delete m_strokeList.RemoveHead();
}
CDocObjectServerDoc::DeleteContents();
}
void CScribDoc::InitDocument()
{
m_bThickPen = FALSE;
m_nThinWidth = 2; // default thin pen is 2 pixels wide
m_nThickWidth = 5; // default thick pen is 5 pixels wide
ReplacePen(); // initialze pen according to current width
// default document size is 2 x 2 inches
m_sizeDoc = CSize(200,200);
}
CStroke* CScribDoc::NewStroke()
{
CStroke* pStrokeItem = new CStroke(m_nPenWidth);
m_strokeList.AddTail(pStrokeItem);
SetModifiedFlag(); // Mark the document as having been modified, for
// purposes of confirming File Close.
return pStrokeItem;
}
/////////////////////////////////////////////////////////////////////////////
// CStroke
IMPLEMENT_SERIAL(CStroke, CObject, 2)
CStroke::CStroke()
{
// This empty constructor should be used by serialization only
}
CStroke::CStroke(UINT nPenWidth)
{
m_nPenWidth = nPenWidth;
m_rectBounding.SetRectEmpty();
}
void CStroke::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
ar << m_rectBounding;
ar << (WORD)m_nPenWidth;
m_pointArray.Serialize(ar);
}
else
{
ar >> m_rectBounding;
WORD w;
ar >> w;
m_nPenWidth = w;
m_pointArray.Serialize(ar);
}
}
BOOL CStroke::DrawStroke(CDC* pDC)
{
CPen penStroke;
if (!penStroke.CreatePen(PS_SOLID, m_nPenWidth, RGB(0,0,0)))
return FALSE;
CPen* pOldPen = pDC->SelectObject(&penStroke);
pDC->MoveTo(m_pointArray[0]);
for (int i=1; i < m_pointArray.GetSize(); i++)
{
pDC->LineTo(m_pointArray[i]);
}
pDC->SelectObject(pOldPen);
return TRUE;
}
void CScribDoc::OnEditClearAll()
{
DeleteContents();
SetModifiedFlag(); // Mark the document as having been modified, for
// purposes of confirming File Close.
UpdateAllViews(NULL);
}
void CScribDoc::OnPenThickOrThin()
{
// Toggle the state of the pen between thin or thick.
m_bThickPen = !m_bThickPen;
// Change the current pen to reflect the new user-specified width.
ReplacePen();
}
void CScribDoc::ReplacePen()
{
m_nPenWidth = m_bThickPen? m_nThickWidth : m_nThinWidth;
// Change the current pen to reflect the new user-specified width.
m_penCur.DeleteObject();
m_penCur.CreatePen(PS_SOLID, m_nPenWidth, RGB(0,0,0)); // solid black
}
void CScribDoc::OnUpdateEditClearAll(CCmdUI* pCmdUI)
{
// Enable the command user interface object (menu item or tool bar
// button) if the document is non-empty, i.e., has at least one stroke.
pCmdUI->Enable(!m_strokeList.IsEmpty());
}
void CScribDoc::OnUpdatePenThickOrThin(CCmdUI* pCmdUI)
{
// Add check mark to Draw Thick Line menu item, if the current
// pen width is "thick".
pCmdUI->SetCheck(m_bThickPen);
}
void CScribDoc::OnPenWidths()
{
CPenWidthsDlg dlg;
// Initialize dialog data
dlg.m_nThinWidth = m_nThinWidth;
dlg.m_nThickWidth = m_nThickWidth;
// Invoke the dialog box
if (dlg.DoModal() == IDOK)
{
// retrieve the dialog data
m_nThinWidth = dlg.m_nThinWidth;
m_nThickWidth = dlg.m_nThickWidth;
// Update the pen that is used by views when drawing new strokes,
// to reflect the new pen width definitions for "thick" and "thin".
ReplacePen();
}
}
void CStroke::FinishStroke()
{
// Calculate the bounding rectangle. It's needed for smart
// repainting.
if (m_pointArray.GetSize()==0)
{
m_rectBounding.SetRectEmpty();
return;
}
CPoint pt = m_pointArray[0];
m_rectBounding = CRect(pt.x, pt.y, pt.x, pt.y);
for (int i=1; i < m_pointArray.GetSize(); i++)
{
// If the point lies outside of the accumulated bounding
// rectangle, then inflate the bounding rect to include it.
pt = m_pointArray[i];
m_rectBounding.left = min(m_rectBounding.left, pt.x);
m_rectBounding.right = max(m_rectBounding.right, pt.x);
m_rectBounding.top = max(m_rectBounding.top, pt.y);
m_rectBounding.bottom = min(m_rectBounding.bottom, pt.y);
}
// Add the pen width to the bounding rectangle. This is necessary
// to account for the width of the stroke when invalidating
// the screen.
m_rectBounding.InflateRect(CSize(m_nPenWidth, -(int)m_nPenWidth));
return;
}
COleServerItem* CScribDoc::OnGetEmbeddedItem()
{
// OnGetEmbeddedItem is called by the framework to get the COleServerItem
// that is associated with the document. It is only called when necessary.
CScribItem* pItem = new CScribItem(this);
ASSERT_VALID(pItem);
return pItem;
}
void CScribDoc::OnSetItemRects(LPCRECT lpPosRect, LPCRECT lpClipRect)
{
// call base class to change the size of the window
CDocObjectServerDoc::OnSetItemRects(lpPosRect, lpClipRect);
// notify first view that scroll info should change
POSITION pos = GetFirstViewPosition();
CScribView* pView = (CScribView*)GetNextView(pos);
pView->SetScrollInfo();
}
void CScribDoc::OnEditCopy()
{
CScribItem* pItem = GetEmbeddedItem();
pItem->CopyToClipboard(TRUE);
}
Scribitm.h
// scribitm.h : interface of the CScribItem class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
class CScribItem : public CDocObjectServerItem
{
DECLARE_DYNAMIC(CScribItem)
// Constructors
public:
CScribItem(CScribDoc* pContainerDoc);
// Attributes
CScribDoc* GetDocument() const
{ return (CScribDoc*)COleServerItem::GetDocument(); }
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CScribItem)
public:
virtual BOOL OnDraw(CDC* pDC, CSize& rSize);
virtual BOOL OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize);
//}}AFX_VIRTUAL
// Implementation
public:
~CScribItem();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
virtual void Serialize(CArchive& ar); // overridden for document i/o
};
/////////////////////////////////////////////////////////////////////////////
Scribitm.cpp
// scribitm.cpp : implementation of the CScribItem class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "scribble.h"
#include "scribdoc.h"
#include "scribitm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScribItem implementation
IMPLEMENT_DYNAMIC(CScribItem, CDocObjectServerItem)
CScribItem::CScribItem(CScribDoc* pContainerDoc)
: CDocObjectServerItem(pContainerDoc, TRUE)
{
// TODO: add one-time construction code here
// (eg, adding additional clipboard formats to the item's data source)
}
CScribItem::~CScribItem()
{
// TODO: add cleanup code here
}
void CScribItem::Serialize(CArchive& ar)
{
// CScribItem::Serialize will be called by the framework if
// the item is copied to the clipboard. This can happen automatically
// through the OLE callback OnGetClipboardData. A good default for
// the embedded item is simply to delegate to the document's Serialize
// function. If you support links, then you will want to serialize
// just a portion of the document.
if (!IsLinkedItem())
{
CScribDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDoc->Serialize(ar);
}
}
BOOL CScribItem::OnGetExtent(DVASPECT dwDrawAspect, CSize& rSize)
{
// This implementation of CScribItem::OnGetExtent only handles
// the "content" aspect indicated by DVASPECT_CONTENT.
if (dwDrawAspect != DVASPECT_CONTENT)
return CDocObjectServerItem::OnGetExtent(dwDrawAspect, rSize);
// CScribItem::OnGetExtent is called to get the extent in
// HIMETRIC units of the entire item. The default implementation
// here simply returns a hard-coded number of units.
CScribDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
rSize = pDoc->GetDocSize();
CClientDC dc(NULL);
// set a MM_LOENGLISH based on logical inches
// (we can't use MM_LOENGLISH because MM_LOENGLISH uses physical inches)
dc.SetMapMode(MM_ANISOTROPIC);
dc.SetViewportExt(dc.GetDeviceCaps(LOGPIXELSX),
dc.GetDeviceCaps(LOGPIXELSY));
dc.SetWindowExt(100, -100);
dc.LPtoHIMETRIC(&rSize);
return TRUE;
}
BOOL CScribItem::OnDraw(CDC* pDC, CSize& /* rSize */)
{
CScribDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->SetMapMode(MM_ANISOTROPIC);
CSize sizeDoc = pDoc->GetDocSize();
sizeDoc.cy = -sizeDoc.cy;
pDC->SetWindowOrg(0,0);
pDC->SetWindowExt(sizeDoc);
CTypedPtrList<CObList,CStroke*>& strokeList = pDoc->m_strokeList;
POSITION pos = strokeList.GetHeadPosition();
while (pos != NULL)
{
strokeList.GetNext(pos)->DrawStroke(pDC);
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CScribItem diagnostics
#ifdef _DEBUG
void CScribItem::AssertValid() const
{
CDocObjectServerItem::AssertValid();
}
void CScribItem::Dump(CDumpContext& dc) const
{
CDocObjectServerItem::Dump(dc);
}
#endif
/////////////////////////////////////////////////////////////////////////////
Scribvw.h
// scribvw.h : interface of the CScribView class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
class CScribView : public CScrollView
{
protected: // create from serialization only
CScribView();
DECLARE_DYNCREATE(CScribView)
// Attributes
public:
CScribDoc* GetDocument();
protected:
CStroke* m_pStrokeCur; // the stroke in progress
CPoint m_ptPrev; // the last mouse pt in the stroke in progress
// Operations
public:
void SetScrollInfo(); // resync scroll sizes
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CScribView)
public:
virtual void OnDraw(CDC* pDC); // overridden to draw this view
virtual void OnInitialUpdate();
virtual void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);
virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL
// Implementation
public:
void PrintTitlePage(CDC* pDC, CPrintInfo* pInfo);
void PrintPageHeader(CDC* pDC, CPrintInfo* pInfo, CString& strHeader);
virtual ~CScribView();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
//{{AFX_MSG(CScribView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnSize(UINT nType, int cx, int cy);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in scribvw.cpp
inline CScribDoc* CScribView::GetDocument()
{ return (CScribDoc*) m_pDocument; }
#endif
/////////////////////////////////////////////////////////////////////////////
Scribvw.cpp
// scribvw.cpp : implementation of the CScribView class
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1995 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "scribble.h"
#include "scribdoc.h"
#include "scribvw.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CScribView
IMPLEMENT_DYNCREATE(CScribView, CScrollView)
BEGIN_MESSAGE_MAP(CScribView, CScrollView)
//{{AFX_MSG_MAP(CScribView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_SIZE()
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CScribView construction/destruction
CScribView::CScribView()
{
SetScrollSizes(MM_TEXT, CSize(0, 0));
}
CScribView::~CScribView()
{
}
/////////////////////////////////////////////////////////////////////////////
// CScribView drawing
void CScribView::OnDraw(CDC* pDC)
{
CScribDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// Get the invalidated rectangle of the view, or in the case
// of printing, the clipping region of the printer dc.
CRect rectClip;
CRect rectStroke;
pDC->GetClipBox(&rectClip);
pDC->LPtoDP(&rectClip);
rectClip.InflateRect(1, 1); // avoid rounding to nothing
// Note: CScrollView::OnPaint() will have already adjusted the
// viewport origin before calling OnDraw(), to reflect the
// currently scrolled position.
// The view delegates the drawing of individual strokes to
// CStroke::DrawStroke().
CTypedPtrList<CObList,CStroke*>& strokeList = pDoc->m_strokeList;
POSITION pos = strokeList.GetHeadPosition();
while (pos != NULL)
{
CStroke* pStroke = strokeList.GetNext(pos);
rectStroke = pStroke->GetBoundingRect();
pDC->LPtoDP(&rectStroke);
rectStroke.InflateRect(1, 1); // avoid rounding to nothing
if (!rectStroke.IntersectRect(&rectStroke, &rectClip))
continue;
pStroke->DrawStroke(pDC);
}
}
/////////////////////////////////////////////////////////////////////////////
// CScribView printing
BOOL CScribView::OnPreparePrinting(CPrintInfo* pInfo)
{
pInfo->SetMaxPage(2); // the document is two pages long:
// the first page is the title page
// the second is the drawing
BOOL bRet = DoPreparePrinting(pInfo); // default preparation
pInfo->m_nNumPreviewPages = 2; // Preview 2 pages at a time
// Set this value after calling DoPreparePrinting to override
// value read from .INI file
return bRet;
}
void CScribView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CScribView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/////////////////////////////////////////////////////////////////////////////
// CScribView diagnostics
#ifdef _DEBUG
void CScribView::AssertValid() const
{
CScrollView::AssertValid();
}
void CScribView::Dump(CDumpContext& dc) const
{
CScrollView::Dump(dc);
}
CScribDoc* CScribView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CScribDoc)));
return (CScribDoc*) m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CScribView message handlers
void CScribView::OnLButtonDown(UINT, CPoint point)
{
// When the user presses the mouse button, she may be
// starting a new stroke, or selecting or de-selecting a stroke.
// CScrollView changes the viewport origin and mapping mode.
// It's necessary to convert the point from device coordinates
// to logical coordinates, such as are stored in the document.
CClientDC dc(this);
OnPrepareDC(&dc);
dc.DPtoLP(&point);
m_pStrokeCur = GetDocument()->NewStroke();
// Add first point to the new stroke
m_pStrokeCur->m_pointArray.Add(point);
SetCapture(); // Capture the mouse until button up.
m_ptPrev = point; // Serves as the MoveTo() anchor point for the
// LineTo() the next point, as the user drags the
// mouse.
return;
}
void CScribView::OnLButtonUp(UINT, CPoint point)
{
// Mouse button up is interesting in the Scribble application
// only if the user is currently drawing a new stroke by dragging
// the captured mouse.
if (GetCapture() != this)
return; // If this window (view) didn't capture the mouse,
// then the user isn't drawing in this window.
CScribDoc* pDoc = GetDocument();
-----------------------------------------------------
// We can't interpret the hint, so assume that anything might
// have been updated.
Invalidate(TRUE);
return;
}
void CScribView::OnInitialUpdate()
{
SetScrollInfo();
CScrollView::OnInitialUpdate();
}
void CScribView::SetScrollInfo()
{
CClientDC dc(NULL);
OnPrepareDC(&dc);
CSize sizeDoc = GetDocument()->GetDocSize();
dc.LPtoDP(&sizeDoc);
SetScrollSizes(MM_TEXT, sizeDoc);
}
void CScribView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
if (pInfo->m_nCurPage == 1) // page no. 1 is the title page
{
PrintTitlePage(pDC, pInfo);
return; // nothing else to print on page 1 but the page title
}
CString strHeader = GetDocument()->GetTitle();
PrintPageHeader(pDC, pInfo, strHeader);
// PrintPageHeader() subtracts out from the pInfo->m_rectDraw the
// amount of the page used for the header.
pDC->SetWindowOrg(pInfo->m_rectDraw.left,-pInfo->m_rectDraw.top);
// Now print the rest of the page
OnDraw(pDC);
}
void CScribView::PrintTitlePage(CDC* pDC, CPrintInfo* pInfo)
{
// Prepare a font size for displaying the file name
LOGFONT logFont;
memset(&logFont, 0, sizeof(LOGFONT));
logFont.lfHeight = 75; // 3/4th inch high in MM_LOENGLISH
// (1/100th inch)
CFont font;
CFont* pOldFont = NULL;
if (font.CreateFontIndirect(&logFont))
pOldFont = pDC->SelectObject(&font);
// Get the file name, to be displayed on title page
CString strPageTitle = GetDocument()->GetTitle();
// Display the file name 1 inch below top of the page,
// centered horizontally
pDC->SetTextAlign(TA_CENTER);
pDC->TextOut(pInfo->m_rectDraw.right/2, -100, strPageTitle);
if (pOldFont != NULL)
pDC->SelectObject(pOldFont);
}
void CScribView::PrintPageHeader(CDC* pDC, CPrintInfo* pInfo,
CString& strHeader)
{
// Print a page header consisting of the name of
// the document and a horizontal line
pDC->TextOut(0,-25, strHeader); // 1/4 inch down
// Draw a line across the page, below the header
TEXTMETRIC textMetric;
pDC->GetTextMetrics(&textMetric);
int y = -35 - textMetric.tmHeight; // line 1/10th inch below text
pDC->MoveTo(0, y); // from left margin
pDC->LineTo(pInfo->m_rectDraw.right, y); // to right margin
// Subtract out from the drawing rectange the space used by the header.
y -= 25; // space 1/4 inch below (top of) line
pInfo->m_rectDraw.top += y;
}
void CScribView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
CScribDoc* pDoc = GetDocument();
CScrollView::OnPrepareDC(pDC, pInfo);
pDC->SetMapMode(MM_ANISOTROPIC);
CSize sizeDoc = pDoc->GetDocSize();
sizeDoc.cy = -sizeDoc.cy;
pDC->SetWindowExt(sizeDoc);
// Binder objects don't scale
int xLogPixPerInch = pDC->GetDeviceCaps(LOGPIXELSX);
int yLogPixPerInch = pDC->GetDeviceCaps(LOGPIXELSY);
long xExt = (long)(sizeDoc.cx * xLogPixPerInch) / 100;
long yExt = (long)(sizeDoc.cy * yLogPixPerInch) / 100;
pDC->SetViewportExt((int)xExt, (int)-yExt);
}
void CScribView::OnSize(UINT nType, int cx, int cy)
{
SetScrollInfo(); // ensure that scroll info is up-to-date
CScrollView::OnSize(nType, cx, cy);
}