Figure 3   WIDGET

WidgView.h


// WidgView.h : interface of the CWidgetView class
//
/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_WIDGVIEW_H__877329C1_C22E_11D0_B2D8_444553540000__INCLUDED_)
#define AFX_WIDGVIEW_H__877329C1_C22E_11D0_B2D8_444553540000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

typedef struct tagWIDGETDATA {
    int nType;      // Widget type (0=Circle, 1=Triangle, 2=Square)
    RECT rcItem;    // Widget rectangle (logical coordinates)
    POINT ptDrag;   // Drag point (logical coordinates)
} WIDGETDATA;

class CWidgetView : public CScrollView
{
protected: // create from serialization only
    CWidgetView();
    DECLARE_DYNCREATE(CWidgetView)

// Attributes
public:
    CWidgetDoc* GetDocument();

// Operations
public:

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CWidgetView)
    public:
    virtual void OnDraw(CDC* pDC);  // overridden to draw this view
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
    virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, 
                                   CPoint point);
    virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, 
                                  CPoint point);
    virtual void OnDragLeave();
    virtual BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, 
                        CPoint point);
    protected:
    virtual void OnInitialUpdate(); // called first time after construct
    virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
    virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
    virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
    //}}AFX_VIRTUAL

// Implementation
public:
    virtual ~CWidgetView();
#ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
    int m_nWidget;
    COleDropTarget m_oleDropTarget;
    CPoint m_ptPrevPos;
    CPoint m_ptOldImage;
    CSize m_sizeDelta;
    CWidget* m_pWidget;
    //{{AFX_MSG(CWidgetView)
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in WidgView.cpp
inline CWidgetDoc* CWidgetView::GetDocument()
   { return (CWidgetDoc*)m_pDocument; }
#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations
   immediately before the previous line.

#endif // !defined(AFX_WIDGVIEW_H__877329C1_C22E_11D0_B2D8_444553540000__INCLUDED_)
WidgView.cpp

// WidgView.cpp : implementation of the CWidgetView class
//

#include "stdafx.h"
#include "Widget.h"
#include "WidgBase.h"
#include "Circle.h"
#include "Triangle.h"
#include "Square.h"
#include "WidgDoc.h"
#include "WidgView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CWidgetView

IMPLEMENT_DYNCREATE(CWidgetView, CScrollView)

BEGIN_MESSAGE_MAP(CWidgetView, CScrollView)
    //{{AFX_MSG_MAP(CWidgetView)
    ON_WM_LBUTTONDOWN()
    ON_WM_CREATE()
    //}}AFX_MSG_MAP
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWidgetView construction/destruction

CWidgetView::CWidgetView()
{
}

CWidgetView::~CWidgetView()
{
}

BOOL CWidgetView::PreCreateWindow(CREATESTRUCT& cs)
{
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs

    return CScrollView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CWidgetView drawing

void CWidgetView::OnDraw(CDC* pDC)
{
    CWidgetDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

    int nCount = pDoc->GetWidgetCount ();
    if (nCount) {
        for (int i=0; i<nCount; i++)
            pDoc->GetWidget (i)->Draw (pDC);
    }
}

void CWidgetView::OnInitialUpdate()
{
    CScrollView::OnInitialUpdate();

    CSize sizeTotal;
    sizeTotal.cx = sizeTotal.cy = 1024;
    SetScrollSizes(MM_TEXT, sizeTotal);

    m_nWidget = -1;     // Index of the widget that's being dragged
    m_pWidget = NULL;   // Pointer to temporary widget used in drag imaging
}

/////////////////////////////////////////////////////////////////////////////
// CWidgetView printing

BOOL CWidgetView::OnPreparePrinting(CPrintInfo* pInfo)
{
    // default preparation
    return DoPreparePrinting(pInfo);
}

void CWidgetView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
    // TODO: add extra initialization before printing
}

void CWidgetView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
    // TODO: add cleanup after printing
}

/////////////////////////////////////////////////////////////////////////////
// CWidgetView diagnostics

#ifdef _DEBUG
void CWidgetView::AssertValid() const
{
    CScrollView::AssertValid();
}

void CWidgetView::Dump(CDumpContext& dc) const
{
    CScrollView::Dump(dc);
}

CWidgetDoc* CWidgetView::GetDocument() // non-debug version is inline
{
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CWidgetDoc)));
    return (CWidgetDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CWidgetView message handlers

void CWidgetView::OnLButtonDown(UINT nFlags, CPoint point) 
{
    CWidgetDoc* pDoc = GetDocument ();
    int nCount = pDoc->GetWidgetCount ();

    if (nCount) {
        //
        // Convert the click point to logical coordinates.
        //
        CClientDC dc (this);
        OnPrepareDC (&dc);
        dc.DPtoLP (&point);

        //
        // Find out whether a widget was clicked.
        //
        int i;
        BOOL bHit = FALSE;
        for (i=nCount - 1; i>=0 && !bHit; i--) {
            CWidget* pWidget = pDoc->GetWidget (i);
            if (pWidget->PtInWidget (point)) {
                bHit = TRUE;
            }
        }

        //
        // If a widget was clicked, initiate a drag-drop operation.
        //
        if (bHit) {
            m_nWidget = ++i;

            HANDLE hData =
                ::GlobalAlloc (GMEM_MOVEABLE | GMEM_SHARE, sizeof (WIDGETDATA));

            WIDGETDATA* pWidgetData = (WIDGETDATA*) ::GlobalLock (hData);
            CWidget* pWidget = pDoc->GetWidget (m_nWidget);
            pWidgetData->nType = pWidget->GetType ();
            pWidget->GetItemRect (&pWidgetData->rcItem);
            pWidgetData->ptDrag = point;
            ::GlobalUnlock (hData);

            COleDataSource ods;
            UINT nFormat = ((CWidgetApp*) AfxGetApp ())->m_nFormat;
            ods.CacheGlobalData (nFormat, hData);

            DROPEFFECT de = ods.DoDragDrop (DROPEFFECT_COPY | DROPEFFECT_MOVE);

            if (de == DROPEFFECT_MOVE) {
                pDoc->RemoveWidget (m_nWidget);
                pDoc->UpdateAllViews (NULL);
            }
            m_nWidget = -1;
        }
    }
    CScrollView::OnLButtonDown(nFlags, point);
}

DROPEFFECT CWidgetView::OnDragEnter(COleDataObject* pDataObject,
                                    DWORD dwKeyState, CPoint point) 
{
    CScrollView::OnDragEnter(pDataObject, dwKeyState, point);

    //
    // Return now if the object being dragged is not a widget.
    //
    UINT nFormat = ((CWidgetApp*) AfxGetApp ())->m_nFormat;
    if (!pDataObject->IsDataAvailable (nFormat))
        return DROPEFFECT_NONE;

    //
    // Create a temporary widget for drag imaging.
    //
    HGLOBAL hData = pDataObject->GetGlobalData (nFormat);

    WIDGETDATA* pWidgetData = (WIDGETDATA*) ::GlobalLock (hData);
    int nType = pWidgetData->nType;
    CRect rect = pWidgetData->rcItem;
    CPoint pt = pWidgetData->ptDrag;
    ::GlobalUnlock (hData);

    switch (nType) {

    case 0: // Circle
        m_pWidget = new CCircle (rect);
        break;

    case 1: // Triangle
        m_pWidget = new CTriangle (rect);
        break;

    case 2: // Square
        m_pWidget = new CSquare (rect);
        break;

    default: // Just in case
        return DROPEFFECT_NONE;
    }

    //
    // Begin dragging.
    //
    CClientDC dc (this);
    OnPrepareDC (&dc);
    dc.DPtoLP (&point);

    m_sizeDelta.cx = pt.x - rect.left;
    m_sizeDelta.cy = pt.y - rect.top;
    CPoint ptDrag (point.x - m_sizeDelta.cx, point.y - m_sizeDelta.cy);
    m_ptOldImage.x = m_ptOldImage.y = -32000;
    m_ptPrevPos = point;

    return (dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
}

DROPEFFECT CWidgetView::OnDragOver(COleDataObject* pDataObject,
                                   DWORD dwKeyState, CPoint point) 
{
    CScrollView::OnDragOver(pDataObject, dwKeyState, point);

    //
    // Return now if the object being dragged is not a widget.
    //
    if (m_pWidget == NULL)
        return DROPEFFECT_NONE;

    //
    // Erase the old drag image and draw a new one if the cursor has moved.
    //
    CClientDC dc (this);
    OnPrepareDC (&dc);
    dc.DPtoLP (&point);

    if (point != m_ptPrevPos) {
        m_pWidget->DrawDragImage (&dc, m_ptOldImage);
        CPoint ptDrag (point.x - m_sizeDelta.cx, point.y - m_sizeDelta.cy);
        m_pWidget->DrawDragImage (&dc, ptDrag);
        m_ptOldImage = ptDrag;
        m_ptPrevPos = point;
    }

    return (dwKeyState & MK_CONTROL) ? DROPEFFECT_COPY : DROPEFFECT_MOVE;
}

void CWidgetView::OnDragLeave() 
{
    CScrollView::OnDragLeave();

    //
    // Erase the old drag image and delete the temporary widget.
    //
    if (m_pWidget != NULL) {
        CClientDC dc (this);
        OnPrepareDC (&dc);
        m_pWidget->DrawDragImage (&dc, m_ptOldImage);
        delete m_pWidget;
        m_pWidget = NULL;
    }
}

BOOL CWidgetView::OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect,
                         CPoint point) 
{
    CScrollView::OnDrop(pDataObject, dropEffect, point);

    //
    // Convert point to logical coordinates.
    //
    CClientDC dc (this);
    OnPrepareDC (&dc);
    dc.DPtoLP (&point);

    //
    // Erase the old drag image and delete the temporary widget.
    //
    if (m_pWidget != NULL) {
        m_pWidget->DrawDragImage (&dc, m_ptOldImage);
        delete m_pWidget;
        m_pWidget = NULL;
    }

    //
    // Retrieve the HGLOBAL from the data object.
    //
    UINT nFormat = ((CWidgetApp*) AfxGetApp ())->m_nFormat;
    HGLOBAL hData = pDataObject->GetGlobalData (nFormat);
    if (hData == NULL)
        return FALSE;

    //
    // Create a widget from the data in the HGLOBAL.
    //
    WIDGETDATA* pWidgetData = (WIDGETDATA*) ::GlobalLock (hData);
    int nType = pWidgetData->nType;
    CRect rect = pWidgetData->rcItem;
    ::GlobalUnlock (hData);

    CRect rcItem;
    rcItem.left = point.x - m_sizeDelta.cx;
    rcItem.top = point.y - m_sizeDelta.cy;
    rcItem.right = rcItem.left + rect.Width ();
    rcItem.bottom = rcItem.top + rect.Height ();

    CWidgetDoc* pDoc = GetDocument ();
    pDoc->AddWidget (nType, &rcItem);
    pDoc->UpdateAllViews (NULL);

    return TRUE;
}

int CWidgetView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
    if (CScrollView::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    m_oleDropTarget.Register (this);
    return 0;
}
WidgDoc.h

// WidgDoc.h : interface of the CWidgetDoc class
//
/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_WIDGDOC_H__877329BF_C22E_11D0_B2D8_444553540000__INCLUDED_)
#define AFX_WIDGDOC_H__877329BF_C22E_11D0_B2D8_444553540000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000


class CWidgetDoc : public CDocument
{
protected: // create from serialization only
    CWidgetDoc();
    DECLARE_DYNCREATE(CWidgetDoc)

// Attributes
public:

// Operations
public:

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CWidgetDoc)
    public:
    virtual BOOL OnNewDocument();
    virtual void Serialize(CArchive& ar);
    virtual void DeleteContents();
    //}}AFX_VIRTUAL

// Implementation
public:
    BOOL RemoveWidget (int nIndex);
    int AddWidget (int nType, LPCRECT pRect);
    CWidget* GetWidget (int nIndex);
    int GetWidgetCount ();
    virtual ~CWidgetDoc();
#ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
    CObArray m_aWidgets;
    //{{AFX_MSG(CWidgetDoc)
    afx_msg void OnInsertTriangle();
    afx_msg void OnInsertCircle();
    afx_msg void OnInsertSquare();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately 
// before the previous line.

#endif // !defined(AFX_WIDGDOC_H__877329BF_C22E_11D0_B2D8_444553540000__INCLUDED_)
WidgDoc.cpp

// WidgDoc.cpp : implementation of the CWidgetDoc class
//

#include "stdafx.h"
#include "Widget.h"
#include "WidgBase.h"
#include "Circle.h"
#include "Triangle.h"
#include "Square.h"
#include "WidgDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CWidgetDoc

IMPLEMENT_DYNCREATE(CWidgetDoc, CDocument)

BEGIN_MESSAGE_MAP(CWidgetDoc, CDocument)
    //{{AFX_MSG_MAP(CWidgetDoc)
    ON_COMMAND(ID_INSERT_TRIANGLE, OnInsertTriangle)
    ON_COMMAND(ID_INSERT_CIRCLE, OnInsertCircle)
    ON_COMMAND(ID_INSERT_SQUARE, OnInsertSquare)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWidgetDoc construction/destruction

CWidgetDoc::CWidgetDoc()
{
    // TODO: add one-time construction code here

}

CWidgetDoc::~CWidgetDoc()
{
}

BOOL CWidgetDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;

    m_aWidgets.SetSize (0, 16);
    return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// CWidgetDoc serialization

void CWidgetDoc::Serialize(CArchive& ar)
{
    m_aWidgets.Serialize (ar);
}

/////////////////////////////////////////////////////////////////////////////
// CWidgetDoc diagnostics

#ifdef _DEBUG
void CWidgetDoc::AssertValid() const
{
    CDocument::AssertValid();
}

void CWidgetDoc::Dump(CDumpContext& dc) const
{
    CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CWidgetDoc commands

void CWidgetDoc::OnInsertCircle() 
{
    AddWidget (0, CRect (10, 10, 100, 100));
    UpdateAllViews (NULL);
}

void CWidgetDoc::OnInsertTriangle() 
{
    AddWidget (1, CRect (10, 10, 100, 100));
    UpdateAllViews (NULL);
}

void CWidgetDoc::OnInsertSquare() 
{
    AddWidget (2, CRect (10, 10, 100, 100));
    UpdateAllViews (NULL);
}

void CWidgetDoc::DeleteContents() 
{
    int nCount = m_aWidgets.GetSize ();
    while (nCount--)
        delete m_aWidgets[nCount];
    m_aWidgets.RemoveAll ();
    
    CDocument::DeleteContents();
}

int CWidgetDoc::GetWidgetCount()
{
    return m_aWidgets.GetSize ();
}

CWidget* CWidgetDoc::GetWidget(int nIndex)
{
    if (nIndex > (m_aWidgets.GetSize () - 1))
        return NULL;
    return (CWidget*) m_aWidgets[nIndex];

}

int CWidgetDoc::AddWidget(int nType, LPCRECT pRect)
{
    int nIndex;
    CWidget* pWidget;

    try {
        switch (nType) {

        case 0: // Circle widget
            pWidget = new CCircle (pRect);
            break;

        case 1: // Triangle widget
            pWidget = new CTriangle (pRect);
            break;

        case 2: // Square widget
            pWidget = new CSquare (pRect);
            break;
        }
        nIndex = m_aWidgets.Add (pWidget);  
    }
    catch (CMemoryException* e) {
        AfxMessageBox ("Out of memory");
        if (pWidget != NULL)
            delete pWidget;
        e->Delete ();
        return -1;
    }
    SetModifiedFlag ();
    return nIndex;
}

BOOL CWidgetDoc::RemoveWidget(int nIndex)
{
    if (nIndex >= m_aWidgets.GetSize ())
        return FALSE;

    delete m_aWidgets[nIndex];
    m_aWidgets.RemoveAt (nIndex);
    return TRUE;
}
Circle.h

#if !defined(AFX_CIRCLE_H__877329CB_C22E_11D0_B2D8_444553540001__INCLUDED_)
#define AFX_CIRCLE_H__877329CB_C22E_11D0_B2D8_444553540001__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Circle.h : header file
//



/////////////////////////////////////////////////////////////////////////////
// CCircle

class CCircle : public CWidget
{
    DECLARE_SERIAL(CCircle)

    CCircle();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:
    virtual ~CCircle();
    virtual int GetType ();
    CCircle (LPCRECT pRect);
    CCircle (int left, int top, int right, int bottom);
    virtual BOOL PtInWidget (POINT point);
    virtual void DrawDragImage (CDC* pDC, POINT point);
    virtual void Draw (CDC* pDC);

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CCircle)
    //}}AFX_VIRTUAL
    virtual void Serialize (CArchive& ar);

// Implementation
protected:

    // Generated message map functions
    //{{AFX_MSG(CCircle)
        // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately 
// before the previous line.

#endif // !defined(AFX_CIRCLE_H__877329CB_C22E_11D0_B2D8_444553540001__INCLUDED_)
Circle.cpp

// Circle.cpp : implementation file
//

#include "stdafx.h"
#include "Widget.h"
#include "WidgBase.h"
#include "Circle.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCircle

IMPLEMENT_SERIAL(CCircle, CWidget, 1)

CCircle::CCircle()
{
}

CCircle::CCircle (LPCRECT pRect)
{
    m_rect = *pRect;
}

CCircle::CCircle (int left, int top, int right, int bottom)
{
    m_rect.SetRect (left, top, right, bottom);
}

CCircle::~CCircle()
{
}

BEGIN_MESSAGE_MAP(CCircle, CWidget)
    //{{AFX_MSG_MAP(CCircle)
        // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CCircle message handlers

void CCircle::Draw(CDC * pDC)
{
    CBrush brush (RGB (255, 255, 0)); // Yellow
    CBrush* pOldBrush = pDC->SelectObject (&brush);
    pDC->Ellipse (m_rect);
    pDC->SelectObject (pOldBrush);
}

void CCircle::DrawDragImage(CDC * pDC, POINT point)
{
    int nOldMode = pDC->SetROP2 (R2_NOT);
    CBrush* pOldBrush = (CBrush*) pDC->SelectStockObject (NULL_BRUSH);

    pDC->Ellipse (point.x, point.y,
                  point.x + m_rect.Width (),
                  point.y + m_rect.Height ());

    pDC->SelectObject (pOldBrush);
    pDC->SetROP2 (nOldMode);
}

BOOL CCircle::PtInWidget(POINT point)
{
    if (!m_rect.PtInRect (point))
        return FALSE;

    CPoint ptCenter;
    ptCenter.x = m_rect.left + (m_rect.Width () / 2);
    ptCenter.y = m_rect.top + (m_rect.Height () / 2);

    int cx = point.x - ptCenter.x;
    int cy = point.y - ptCenter.y;

    if ((cx * cx) + (cy * cy) <
        (m_rect.Width () / 2) * (m_rect.Width () / 2))
        return TRUE;

    return FALSE;
}

int CCircle::GetType()
{
    return 0; // Circle
}

void CCircle::Serialize (CArchive& ar)
{
    CWidget::Serialize (ar);

    if (ar.IsStoring ())
        ar << m_rect;
    else
        ar >> m_rect;
}
Triangle.h

#if !defined(AFX_TRIANGLE_H__877329CB_C22E_11D0_B2D8_444553540000__INCLUDED_)
#define AFX_TRIANGLE_H__877329CB_C22E_11D0_B2D8_444553540000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Triangle.h : header file
//



/////////////////////////////////////////////////////////////////////////////
// CTriangle

class CTriangle : public CWidget
{
    DECLARE_SERIAL(CTriangle)

    CTriangle();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:
    virtual ~CTriangle();
    virtual int GetType ();
    CTriangle (LPCRECT pRect);
    CTriangle (int left, int top, int right, int bottom);
    virtual BOOL PtInWidget (POINT point);
    virtual void DrawDragImage (CDC* pDC, POINT point);
    virtual void Draw (CDC* pDC);

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CTriangle)
    //}}AFX_VIRTUAL
    virtual void Serialize (CArchive& ar);

// Implementation
protected:

    // Generated message map functions
    //{{AFX_MSG(CTriangle)
        // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately 
// before the previous line.

#endif // !defined(AFX_TRIANGLE_H__877329CB_C22E_11D0_B2D8_444553540000__INCLUDED_)
Triangle.cpp

// Triangle.cpp : implementation file
//

#include "stdafx.h"
#include "Widget.h"
#include "WidgBase.h"
#include "Triangle.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTriangle

IMPLEMENT_SERIAL(CTriangle, CWidget, 1)

CTriangle::CTriangle()
{
}

CTriangle::CTriangle (LPCRECT pRect)
{
    m_rect = *pRect;
}

CTriangle::CTriangle (int left, int top, int right, int bottom)
{
    m_rect.SetRect (left, top, right, bottom);
}

CTriangle::~CTriangle()
{
}

BEGIN_MESSAGE_MAP(CTriangle, CWidget)
    //{{AFX_MSG_MAP(CTriangle)
        // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTriangle message handlers

void CTriangle::Draw(CDC * pDC)
{
    CBrush brush (RGB (0, 0, 255)); // Blue
    CBrush* pOldBrush = pDC->SelectObject (&brush);

    CPoint points[3];
    points[0].x = m_rect.left;
    points[0].y = m_rect.bottom;
    points[1].x = m_rect.left + ((m_rect.right - m_rect.left) / 2);
    points[1].y = m_rect.top;
    points[2].x = m_rect.right;
    points[2].y = m_rect.bottom;
    pDC->Polygon (points, 3);

    pDC->SelectObject (pOldBrush);
}

void CTriangle::DrawDragImage(CDC * pDC, POINT point)
{
    int nOldMode = pDC->SetROP2 (R2_NOT);
    CBrush* pOldBrush = (CBrush*) pDC->SelectStockObject (NULL_BRUSH);

    CPoint points[3];
    points[0].x = point.x;
    points[0].y = point.y + m_rect.Height ();
    points[1].x = point.x + (m_rect.Width () / 2);
    points[1].y = point.y;
    points[2].x = point.x + m_rect.Width ();
    points[2].y = point.y + m_rect.Height ();
    pDC->Polygon (points, 3);

    pDC->SelectObject (pOldBrush);
    pDC->SetROP2 (nOldMode);
}

BOOL CTriangle::PtInWidget(POINT point)
{
    if (!m_rect.PtInRect (point))
        return FALSE;

    int cx = min (point.x - m_rect.left, m_rect.right - point.x);
    return ((m_rect.bottom - point.y) <= (2 * cx));
}

int CTriangle::GetType()
{
    return 1; // Triangle
}

void CTriangle::Serialize (CArchive& ar)
{
    CWidget::Serialize (ar);

    if (ar.IsStoring ())
        ar << m_rect;
    else
        ar >> m_rect;
}
Square.h

#if !defined(AFX_SQUARE_H__877329CB_C22E_11D0_B2D8_444553540002__INCLUDED_)
#define AFX_SQUARE_H__877329CB_C22E_11D0_B2D8_444553540002__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// Square.h : header file
//


/////////////////////////////////////////////////////////////////////////////
// CSquare

class CSquare : public CWidget
{
    DECLARE_SERIAL(CSquare)

    CSquare();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:
    virtual ~CSquare();
    virtual int GetType ();
    CSquare (LPCRECT pRect);
    CSquare (int left, int top, int right, int bottom);
    virtual BOOL PtInWidget (POINT point);
    virtual void DrawDragImage (CDC* pDC, POINT point);
    virtual void Draw (CDC* pDC);

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CSquare)
    //}}AFX_VIRTUAL
    virtual void Serialize (CArchive& ar);

// Implementation
protected:

    // Generated message map functions
    //{{AFX_MSG(CSquare)
        // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately 
// before the previous line.

#endif // !defined(AFX_SQUARE_H__877329CB_C22E_11D0_B2D8_444553540002__INCLUDED_)
Square.cpp

// Square.cpp : implementation file
//

#include "stdafx.h"
#include "Widget.h"
#include "WidgBase.h"
#include "Square.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CSquare

IMPLEMENT_SERIAL(CSquare, CWidget, 1)

CSquare::CSquare()
{
}

CSquare::CSquare (LPCRECT pRect)
{
    m_rect = *pRect;
}

CSquare::CSquare (int left, int top, int right, int bottom)
{
    m_rect.SetRect (left, top, right, bottom);
}

CSquare::~CSquare()
{
}

BEGIN_MESSAGE_MAP(CSquare, CWidget)
    //{{AFX_MSG_MAP(CSquare)
        // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSquare message handlers

void CSquare::Draw(CDC * pDC)
{
    CBrush brush (RGB (255, 0, 0)); // Red
    CBrush* pOldBrush = pDC->SelectObject (&brush);
    pDC->Rectangle (m_rect);
    pDC->SelectObject (pOldBrush);
}

void CSquare::DrawDragImage(CDC * pDC, POINT point)
{
    int nOldMode = pDC->SetROP2 (R2_NOT);
    CBrush* pOldBrush = (CBrush*) pDC->SelectStockObject (NULL_BRUSH);

    pDC->Rectangle (point.x, point.y,
                    point.x + m_rect.Width (),
                    point.y + m_rect.Height ());

    pDC->SelectObject (pOldBrush);
    pDC->SetROP2 (nOldMode);
}

BOOL CSquare::PtInWidget(POINT point)
{
    return m_rect.PtInRect (point);
}

int CSquare::GetType()
{
    return 2; // Square
}

void CSquare::Serialize (CArchive& ar)
{
    CWidget::Serialize (ar);

    if (ar.IsStoring ())
        ar << m_rect;
    else
        ar >> m_rect;
}
WidgBase.h

#if !defined(AFX_WIDGBASE_H__877329CA_C22E_11D0_B2D8_444553540000__INCLUDED_)
#define AFX_WIDGBASE_H__877329CA_C22E_11D0_B2D8_444553540000__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// WidgBase.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CWidget command target

class CWidget : public CCmdTarget
{
    DECLARE_DYNCREATE(CWidget)

    CWidget();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:
    virtual void GetItemRect (LPRECT pRect);
    virtual ~CWidget();
    virtual int GetType ();
    virtual BOOL PtInWidget (POINT point);
    virtual void DrawDragImage (CDC* pDC, POINT point);
    virtual void Draw (CDC* pDC);

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CWidget)
    //}}AFX_VIRTUAL

// Implementation
protected:
    CRect m_rect;

    // Generated message map functions
    //{{AFX_MSG(CWidget)
        // NOTE - the ClassWizard will add and remove member functions here.
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Developer Studio will insert additional declarations immediately 
// before the previous line.

#endif // !defined(AFX_WIDGBASE_H__877329CA_C22E_11D0_B2D8_444553540000__INCLUDED_)
WidgBase.cpp

// WidgBase.cpp : implementation file
//

#include "stdafx.h"
#include "Widget.h"
#include "WidgBase.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CWidget

IMPLEMENT_DYNCREATE(CWidget, CCmdTarget)

CWidget::CWidget()
{
}

CWidget::~CWidget()
{
}

BEGIN_MESSAGE_MAP(CWidget, CCmdTarget)
    //{{AFX_MSG_MAP(CWidget)
        // NOTE - the ClassWizard will add and remove mapping macros here.
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CWidget message handlers

void CWidget::Draw(CDC * pDC)
{
    ASSERT (FALSE); // Override this function in a derived class
}

void CWidget::DrawDragImage(CDC * pDC, POINT point)
{
    ASSERT (FALSE); // Override this function in a derived class
}

BOOL CWidget::PtInWidget(POINT point)
{
    ASSERT (FALSE); // Override this function in a derived class
    return FALSE;
}

int CWidget::GetType()
{
    ASSERT (FALSE); // Override this function in a derived class
    return -1;
}

void CWidget::GetItemRect(LPRECT pRect)
{
    *pRect = m_rect;
}

Figure 4   Saving a Widget's Address


 HGLOBAL hData = pDataObject->GetGlobalData (nFormat);
 WIDGETDATA* pWidgetData = (WIDGETDATA*) ::GlobalLock (hData);
 int nType =  pWidgetData->nType;
 CRect rect = pWidgetData->rcItem;
 CPoint pt =  pWidgetData->ptDrag;
 ::GlobalUnlock (hData);
 
 switch (nType) {
 case 0: // Circle
     m_pWidget = new CCircle (rect);
     break;
 case 1: // Triangle
     m_pWidget = new CTriangle (rect);
     break;
 case 2: // Square
     m_pWidget = new CSquare (rect);
     break;
 default: // Just in case
     return DROPEFFECT_NONE;
 }