home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / ole / drawcli / drawobj.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-03-27  |  21.8 KB  |  1,112 lines

  1. // drawobj.cpp - implementation for drawing objects
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13.  
  14. #include "stdafx.h"
  15. #include "drawcli.h"
  16.  
  17. #include "drawdoc.h"
  18. #include "drawvw.h"
  19. #include "drawobj.h"
  20.  
  21. #include "cntritem.h"
  22. #include "rectdlg.h"
  23.  
  24. IMPLEMENT_SERIAL(CDrawObj, CObject, 0)
  25.  
  26. CDrawObj::CDrawObj()
  27. {
  28. }
  29.  
  30. CDrawObj::~CDrawObj()
  31. {
  32. }
  33.  
  34. CDrawObj::CDrawObj(const CRect& position)
  35. {
  36.     m_position = position;
  37.     m_pDocument = NULL;
  38.  
  39.     m_bPen = TRUE;
  40.     m_logpen.lopnStyle = PS_INSIDEFRAME;
  41.     m_logpen.lopnWidth.x = 1;
  42.     m_logpen.lopnWidth.y = 1;
  43.     m_logpen.lopnColor = RGB(0, 0, 0);
  44.  
  45.     m_bBrush = TRUE;
  46.     m_logbrush.lbStyle = BS_SOLID;
  47.     m_logbrush.lbColor = RGB(192, 192, 192);
  48.     m_logbrush.lbHatch = HS_HORIZONTAL;
  49. }
  50.  
  51. void CDrawObj::Serialize(CArchive& ar)
  52. {
  53.     CObject::Serialize(ar);
  54.     if (ar.IsStoring())
  55.     {
  56.         ar << m_position;
  57.         ar << (WORD)m_bPen;
  58.         ar.Write(&m_logpen, sizeof(LOGPEN));
  59.         ar << (WORD)m_bBrush;
  60.         ar.Write(&m_logbrush, sizeof(LOGBRUSH));
  61.     }
  62.     else
  63.     {
  64.         // get the document back pointer from the archive
  65.         m_pDocument = (CDrawDoc*)ar.m_pDocument;
  66.         ASSERT_VALID(m_pDocument);
  67.         ASSERT_KINDOF(CDrawDoc, m_pDocument);
  68.  
  69.         WORD wTemp;
  70.         ar >> m_position;
  71.         ar >> wTemp; m_bPen = (BOOL)wTemp;
  72.         ar.Read(&m_logpen,sizeof(LOGPEN));
  73.         ar >> wTemp; m_bBrush = (BOOL)wTemp;
  74.         ar.Read(&m_logbrush, sizeof(LOGBRUSH));
  75.     }
  76. }
  77.  
  78. void CDrawObj::Remove()
  79. {
  80.     delete this;
  81. }
  82.  
  83. void CDrawObj::Draw(CDC*)
  84. {
  85. }
  86.  
  87. void CDrawObj::DrawTracker(CDC* pDC, TrackerState state)
  88. {
  89.     ASSERT_VALID(this);
  90.  
  91.     switch (state)
  92.     {
  93.     case normal:
  94.         break;
  95.  
  96.     case selected:
  97.     case active:
  98.         {
  99.             int nHandleCount = GetHandleCount();
  100.             for (int nHandle = 1; nHandle <= nHandleCount; nHandle += 1)
  101.             {
  102.                 CPoint handle = GetHandle(nHandle);
  103.                 pDC->PatBlt(handle.x - 3, handle.y - 3, 7, 7, DSTINVERT);
  104.             }
  105.         }
  106.         break;
  107.     }
  108. }
  109.  
  110. // position is in logical
  111. void CDrawObj::MoveTo(const CRect& position, CDrawView* pView)
  112. {
  113.     ASSERT_VALID(this);
  114.  
  115.     if (position == m_position)
  116.         return;
  117.  
  118.     if (pView == NULL)
  119.     {
  120.         Invalidate();
  121.         m_position = position;
  122.         Invalidate();
  123.     }
  124.     else
  125.     {
  126.         pView->InvalObj(this);
  127.         m_position = position;
  128.         pView->InvalObj(this);
  129.     }
  130.     m_pDocument->SetModifiedFlag();
  131. }
  132.  
  133. // Note: if bSelected, hit-codes start at one for the top-left
  134. // and increment clockwise, 0 means no hit.
  135. // If !bSelected, 0 = no hit, 1 = hit (anywhere)
  136.  
  137. // point is in logical coordinates
  138. int CDrawObj::HitTest(CPoint point, CDrawView* pView, BOOL bSelected)
  139. {
  140.     ASSERT_VALID(this);
  141.     ASSERT(pView != NULL);
  142.  
  143.     if (bSelected)
  144.     {
  145.         int nHandleCount = GetHandleCount();
  146.         for (int nHandle = 1; nHandle <= nHandleCount; nHandle += 1)
  147.         {
  148.             // GetHandleRect returns in logical coords
  149.             CRect rc = GetHandleRect(nHandle,pView);
  150.             if (point.x >= rc.left && point.x < rc.right &&
  151.                 point.y <= rc.top && point.y > rc.bottom)
  152.                 return nHandle;
  153.         }
  154.     }
  155.     else
  156.     {
  157.         if (point.x >= m_position.left && point.x < m_position.right &&
  158.             point.y <= m_position.top && point.y > m_position.bottom)
  159.             return 1;
  160.     }
  161.     return 0;
  162. }
  163.  
  164. // rect must be in logical coordinates
  165. BOOL CDrawObj::Intersects(const CRect& rect)
  166. {
  167.     ASSERT_VALID(this);
  168.  
  169.     CRect fixed = m_position;
  170.     fixed.NormalizeRect();
  171.     CRect rectT = rect;
  172.     rectT.NormalizeRect();
  173.     return !(rectT & fixed).IsRectEmpty();
  174. }
  175.  
  176. int CDrawObj::GetHandleCount()
  177. {
  178.     ASSERT_VALID(this);
  179.     return 8;
  180. }
  181.  
  182. // returns logical coords of center of handle
  183. CPoint CDrawObj::GetHandle(int nHandle)
  184. {
  185.     ASSERT_VALID(this);
  186.     int x, y, xCenter, yCenter;
  187.  
  188.     // this gets the center regardless of left/right and top/bottom ordering
  189.     xCenter = m_position.left + m_position.Width() / 2;
  190.     yCenter = m_position.top + m_position.Height() / 2;
  191.  
  192.     switch (nHandle)
  193.     {
  194.     default:
  195.         ASSERT(FALSE);
  196.  
  197.     case 1:
  198.         x = m_position.left;
  199.         y = m_position.top;
  200.         break;
  201.  
  202.     case 2:
  203.         x = xCenter;
  204.         y = m_position.top;
  205.         break;
  206.  
  207.     case 3:
  208.         x = m_position.right;
  209.         y = m_position.top;
  210.         break;
  211.  
  212.     case 4:
  213.         x = m_position.right;
  214.         y = yCenter;
  215.         break;
  216.  
  217.     case 5:
  218.         x = m_position.right;
  219.         y = m_position.bottom;
  220.         break;
  221.  
  222.     case 6:
  223.         x = xCenter;
  224.         y = m_position.bottom;
  225.         break;
  226.  
  227.     case 7:
  228.         x = m_position.left;
  229.         y = m_position.bottom;
  230.         break;
  231.  
  232.     case 8:
  233.         x = m_position.left;
  234.         y = yCenter;
  235.         break;
  236.     }
  237.  
  238.     return CPoint(x, y);
  239. }
  240.  
  241. // return rectange of handle in logical coords
  242. CRect CDrawObj::GetHandleRect(int nHandleID, CDrawView* pView)
  243. {
  244.     ASSERT_VALID(this);
  245.     ASSERT(pView != NULL);
  246.  
  247.     CRect rect;
  248.     // get the center of the handle in logical coords
  249.     CPoint point = GetHandle(nHandleID);
  250.     // convert to client/device coords
  251.     pView->DocToClient(point);
  252.     // return CRect of handle in device coords
  253.     rect.SetRect(point.x-3, point.y-3, point.x+3, point.y+3);
  254.     pView->ClientToDoc(rect);
  255.  
  256.     return rect;
  257. }
  258.  
  259. HCURSOR CDrawObj::GetHandleCursor(int nHandle)
  260. {
  261.     ASSERT_VALID(this);
  262.  
  263.     LPCTSTR id;
  264.     switch (nHandle)
  265.     {
  266.     default:
  267.         ASSERT(FALSE);
  268.  
  269.     case 1:
  270.     case 5:
  271.         id = IDC_SIZENWSE;
  272.         break;
  273.  
  274.     case 2:
  275.     case 6:
  276.         id = IDC_SIZENS;
  277.         break;
  278.  
  279.     case 3:
  280.     case 7:
  281.         id = IDC_SIZENESW;
  282.         break;
  283.  
  284.     case 4:
  285.     case 8:
  286.         id = IDC_SIZEWE;
  287.         break;
  288.     }
  289.  
  290.     return AfxGetApp()->LoadStandardCursor(id);
  291. }
  292.  
  293. // point must be in logical
  294. void CDrawObj::MoveHandleTo(int nHandle, CPoint point, CDrawView* pView)
  295. {
  296.     ASSERT_VALID(this);
  297.  
  298.     CRect position = m_position;
  299.     switch (nHandle)
  300.     {
  301.     default:
  302.         ASSERT(FALSE);
  303.  
  304.     case 1:
  305.         position.left = point.x;
  306.         position.top = point.y;
  307.         break;
  308.  
  309.     case 2:
  310.         position.top = point.y;
  311.         break;
  312.  
  313.     case 3:
  314.         position.right = point.x;
  315.         position.top = point.y;
  316.         break;
  317.  
  318.     case 4:
  319.         position.right = point.x;
  320.         break;
  321.  
  322.     case 5:
  323.         position.right = point.x;
  324.         position.bottom = point.y;
  325.         break;
  326.  
  327.     case 6:
  328.         position.bottom = point.y;
  329.         break;
  330.  
  331.     case 7:
  332.         position.left = point.x;
  333.         position.bottom = point.y;
  334.         break;
  335.  
  336.     case 8:
  337.         position.left = point.x;
  338.         break;
  339.     }
  340.  
  341.     MoveTo(position, pView);
  342. }
  343.  
  344. void CDrawObj::Invalidate()
  345. {
  346.     ASSERT_VALID(this);
  347.     m_pDocument->UpdateAllViews(NULL, HINT_UPDATE_DRAWOBJ, this);
  348. }
  349.  
  350. CDrawObj* CDrawObj::Clone(CDrawDoc* pDoc)
  351. {
  352.     ASSERT_VALID(this);
  353.  
  354.     CDrawObj* pClone = new CDrawObj(m_position);
  355.     pClone->m_bPen = m_bPen;
  356.     pClone->m_logpen = m_logpen;
  357.     pClone->m_bBrush = m_bBrush;
  358.     pClone->m_logbrush = m_logbrush;
  359.     ASSERT_VALID(pClone);
  360.  
  361.     if (pDoc != NULL)
  362.         pDoc->Add(pClone);
  363.  
  364.     return pClone;
  365. }
  366.  
  367. void CDrawObj::OnEditProperties()
  368. {
  369.     ASSERT_VALID(this);
  370.  
  371.     CPropertySheet sheet( _T("Shape Properties") );
  372.     CRectDlg dlg;
  373.     dlg.m_bNoFill = !m_bBrush;
  374.     dlg.m_penSize = m_bPen ? m_logpen.lopnWidth.x : 0;
  375.     sheet.AddPage( &dlg );
  376.  
  377.     if (sheet.DoModal() != IDOK)
  378.         return;
  379.  
  380.     m_bBrush = !dlg.m_bNoFill;
  381.     m_bPen = dlg.m_penSize > 0;
  382.     if (m_bPen)
  383.     {
  384.         m_logpen.lopnWidth.x = dlg.m_penSize;
  385.         m_logpen.lopnWidth.y = dlg.m_penSize;
  386.     }
  387.  
  388.     Invalidate();
  389.     m_pDocument->SetModifiedFlag();
  390. }
  391.  
  392. void CDrawObj::OnOpen(CDrawView* /*pView*/ )
  393. {
  394.     OnEditProperties();
  395. }
  396.  
  397. void CDrawObj::SetLineColor(COLORREF color)
  398. {
  399.     ASSERT_VALID(this);
  400.  
  401.     m_logpen.lopnColor = color;
  402.     Invalidate();
  403.     m_pDocument->SetModifiedFlag();
  404. }
  405.  
  406. void CDrawObj::SetFillColor(COLORREF color)
  407. {
  408.     ASSERT_VALID(this);
  409.  
  410.     m_logbrush.lbColor = color;
  411.     Invalidate();
  412.     m_pDocument->SetModifiedFlag();
  413. }
  414.  
  415. #ifdef _DEBUG
  416. void CDrawObj::AssertValid()
  417. {
  418.     ASSERT(m_position.left <= m_position.right);
  419.     ASSERT(m_position.bottom <= m_position.top);
  420. }
  421. #endif
  422.  
  423. ////////////////////////////////////////////////////////////////////////////
  424. // CDrawRect
  425.  
  426. IMPLEMENT_SERIAL(CDrawRect, CDrawObj, 0)
  427.  
  428. CDrawRect::CDrawRect()
  429. {
  430. }
  431.  
  432. CDrawRect::CDrawRect(const CRect& position)
  433.     : CDrawObj(position)
  434. {
  435.     ASSERT_VALID(this);
  436.  
  437.     m_nShape = rectangle;
  438.     m_roundness.x = 16;
  439.     m_roundness.y = 16;
  440. }
  441.  
  442. void CDrawRect::Serialize(CArchive& ar)
  443. {
  444.     ASSERT_VALID(this);
  445.  
  446.     CDrawObj::Serialize(ar);
  447.     if (ar.IsStoring())
  448.     {
  449.         ar << (WORD) m_nShape;
  450.         ar << m_roundness;
  451.     }
  452.     else
  453.     {
  454.         WORD wTemp;
  455.         ar >> wTemp; m_nShape = (Shape)wTemp;
  456.         ar >> m_roundness;
  457.     }
  458. }
  459.  
  460. void CDrawRect::Draw(CDC* pDC)
  461. {
  462.     ASSERT_VALID(this);
  463.  
  464.     CBrush brush;
  465.     if (!brush.CreateBrushIndirect(&m_logbrush))
  466.         return;
  467.     CPen pen;
  468.     if (!pen.CreatePenIndirect(&m_logpen))
  469.         return;
  470.  
  471.     CBrush* pOldBrush;
  472.     CPen* pOldPen;
  473.  
  474.     if (m_bBrush)
  475.         pOldBrush = pDC->SelectObject(&brush);
  476.     else
  477.         pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
  478.  
  479.     if (m_bPen)
  480.         pOldPen = pDC->SelectObject(&pen);
  481.     else
  482.         pOldPen = (CPen*)pDC->SelectStockObject(NULL_PEN);
  483.  
  484.     CRect rect = m_position;
  485.     switch (m_nShape)
  486.     {
  487.     case rectangle:
  488.         pDC->Rectangle(rect);
  489.         break;
  490.  
  491.     case roundRectangle:
  492.         pDC->RoundRect(rect, m_roundness);
  493.         break;
  494.  
  495.     case ellipse:
  496.         pDC->Ellipse(rect);
  497.         break;
  498.  
  499.     case line:
  500.         if (rect.top > rect.bottom)
  501.         {
  502.             rect.top -= m_logpen.lopnWidth.y / 2;
  503.             rect.bottom += (m_logpen.lopnWidth.y + 1) / 2;
  504.         }
  505.         else
  506.         {
  507.             rect.top += (m_logpen.lopnWidth.y + 1) / 2;
  508.             rect.bottom -= m_logpen.lopnWidth.y / 2;
  509.         }
  510.  
  511.         if (rect.left > rect.right)
  512.         {
  513.             rect.left -= m_logpen.lopnWidth.x / 2;
  514.             rect.right += (m_logpen.lopnWidth.x + 1) / 2;
  515.         }
  516.         else
  517.         {
  518.             rect.left += (m_logpen.lopnWidth.x + 1) / 2;
  519.             rect.right -= m_logpen.lopnWidth.x / 2;
  520.         }
  521.  
  522.         pDC->MoveTo(rect.TopLeft());
  523.         pDC->LineTo(rect.BottomRight());
  524.         break;
  525.     }
  526.  
  527.     pDC->SelectObject(pOldBrush);
  528.     pDC->SelectObject(pOldPen);
  529. }
  530.  
  531.  
  532. int CDrawRect::GetHandleCount()
  533. {
  534.     ASSERT_VALID(this);
  535.  
  536.     return m_nShape == line ? 2 :
  537.         CDrawObj::GetHandleCount() + (m_nShape == roundRectangle);
  538. }
  539.  
  540. // returns center of handle in logical coordinates
  541. CPoint CDrawRect::GetHandle(int nHandle)
  542. {
  543.     ASSERT_VALID(this);
  544.  
  545.     if (m_nShape == line && nHandle == 2)
  546.         nHandle = 5;
  547.     else if (m_nShape == roundRectangle && nHandle == 9)
  548.     {
  549.         CRect rect = m_position;
  550.         rect.NormalizeRect();
  551.         CPoint point = rect.BottomRight();
  552.         point.x -= m_roundness.x / 2;
  553.         point.y -= m_roundness.y / 2;
  554.         return point;
  555.     }
  556.  
  557.     return CDrawObj::GetHandle(nHandle);
  558. }
  559.  
  560. HCURSOR CDrawRect::GetHandleCursor(int nHandle)
  561. {
  562.     ASSERT_VALID(this);
  563.  
  564.     if (m_nShape == line && nHandle == 2)
  565.         nHandle = 5;
  566.     else if (m_nShape == roundRectangle && nHandle == 9)
  567.         return AfxGetApp()->LoadStandardCursor(IDC_SIZEALL);
  568.     return CDrawObj::GetHandleCursor(nHandle);
  569. }
  570.  
  571. // point is in logical coordinates
  572. void CDrawRect::MoveHandleTo(int nHandle, CPoint point, CDrawView* pView)
  573. {
  574.     ASSERT_VALID(this);
  575.  
  576.     if (m_nShape == line && nHandle == 2)
  577.         nHandle = 5;
  578.     else if (m_nShape == roundRectangle && nHandle == 9)
  579.     {
  580.         CRect rect = m_position;
  581.         rect.NormalizeRect();
  582.         if (point.x > rect.right - 1)
  583.             point.x = rect.right - 1;
  584.         else if (point.x < rect.left + rect.Width() / 2)
  585.             point.x = rect.left + rect.Width() / 2;
  586.         if (point.y > rect.bottom - 1)
  587.             point.y = rect.bottom - 1;
  588.         else if (point.y < rect.top + rect.Height() / 2)
  589.             point.y = rect.top + rect.Height() / 2;
  590.         m_roundness.x = 2 * (rect.right - point.x);
  591.         m_roundness.y = 2 * (rect.bottom - point.y);
  592.         m_pDocument->SetModifiedFlag();
  593.         if (pView == NULL)
  594.             Invalidate();
  595.         else
  596.             pView->InvalObj(this);
  597.         return;
  598.     }
  599.  
  600.     CDrawObj::MoveHandleTo(nHandle, point, pView);
  601. }
  602.  
  603. // rect must be in logical coordinates
  604. BOOL CDrawRect::Intersects(const CRect& rect)
  605. {
  606.     ASSERT_VALID(this);
  607.  
  608.     CRect rectT = rect;
  609.     rectT.NormalizeRect();
  610.  
  611.     CRect fixed = m_position;
  612.     fixed.NormalizeRect();
  613.     if ((rectT & fixed).IsRectEmpty())
  614.         return FALSE;
  615.  
  616.     CRgn rgn;
  617.     switch (m_nShape)
  618.     {
  619.     case rectangle:
  620.         return TRUE;
  621.  
  622.     case roundRectangle:
  623.         rgn.CreateRoundRectRgn(fixed.left, fixed.top, fixed.right, fixed.bottom,
  624.             m_roundness.x, m_roundness.y);
  625.         break;
  626.  
  627.     case ellipse:
  628.         rgn.CreateEllipticRgnIndirect(fixed);
  629.         break;
  630.  
  631.     case line:
  632.         {
  633.             int x = (m_logpen.lopnWidth.x + 5) / 2;
  634.             int y = (m_logpen.lopnWidth.y + 5) / 2;
  635.             POINT points[4];
  636.             points[0].x = fixed.left;
  637.             points[0].y = fixed.top;
  638.             points[1].x = fixed.left;
  639.             points[1].y = fixed.top;
  640.             points[2].x = fixed.right;
  641.             points[2].y = fixed.bottom;
  642.             points[3].x = fixed.right;
  643.             points[3].y = fixed.bottom;
  644.  
  645.             if (fixed.left < fixed.right)
  646.             {
  647.                 points[0].x -= x;
  648.                 points[1].x += x;
  649.                 points[2].x += x;
  650.                 points[3].x -= x;
  651.             }
  652.             else
  653.             {
  654.                 points[0].x += x;
  655.                 points[1].x -= x;
  656.                 points[2].x -= x;
  657.                 points[3].x += x;
  658.             }
  659.  
  660.             if (fixed.top < fixed.bottom)
  661.             {
  662.                 points[0].y -= y;
  663.                 points[1].y += y;
  664.                 points[2].y += y;
  665.                 points[3].y -= y;
  666.             }
  667.             else
  668.             {
  669.                 points[0].y += y;
  670.                 points[1].y -= y;
  671.                 points[2].y -= y;
  672.                 points[3].y += y;
  673.             }
  674.             rgn.CreatePolygonRgn(points, 4, ALTERNATE);
  675.         }
  676.         break;
  677.     }
  678.     return rgn.RectInRegion(fixed);
  679. }
  680.  
  681. CDrawObj* CDrawRect::Clone(CDrawDoc* pDoc)
  682. {
  683.     ASSERT_VALID(this);
  684.  
  685.     CDrawRect* pClone = new CDrawRect(m_position);
  686.     pClone->m_bPen = m_bPen;
  687.     pClone->m_logpen = m_logpen;
  688.     pClone->m_bBrush = m_bBrush;
  689.     pClone->m_logbrush = m_logbrush;
  690.     pClone->m_nShape = m_nShape;
  691.     pClone->m_roundness = m_roundness;
  692.     ASSERT_VALID(pClone);
  693.  
  694.     if (pDoc != NULL)
  695.         pDoc->Add(pClone);
  696.  
  697.     ASSERT_VALID(pClone);
  698.     return pClone;
  699. }
  700.  
  701. ////////////////////////////////////////////////////////////////////////////
  702. // CDrawPoly
  703.  
  704. IMPLEMENT_SERIAL(CDrawPoly, CDrawObj, 0)
  705.  
  706. CDrawPoly::CDrawPoly()
  707. {
  708.     m_points = NULL;
  709.     m_nPoints = 0;
  710.     m_nAllocPoints = 0;
  711. }
  712.  
  713. CDrawPoly::CDrawPoly(const CRect& position)
  714.     : CDrawObj(position)
  715. {
  716.     m_points = NULL;
  717.     m_nPoints = 0;
  718.     m_nAllocPoints = 0;
  719.     m_bPen = TRUE;
  720.     m_bBrush = FALSE;
  721. }
  722.  
  723. CDrawPoly::~CDrawPoly()
  724. {
  725.     if (m_points != NULL)
  726.         delete[] m_points;
  727. }
  728.  
  729. void CDrawPoly::Serialize( CArchive& ar )
  730. {
  731.     int i;
  732.     CDrawObj::Serialize( ar );
  733.     if( ar.IsStoring() )
  734.     {
  735.         ar << (WORD) m_nPoints;
  736.         ar << (WORD) m_nAllocPoints;
  737.         for (i = 0;i< m_nPoints; i++)
  738.             ar << m_points[i];
  739.     }
  740.     else
  741.     {
  742.         WORD wTemp;
  743.         ar >> wTemp; m_nPoints = wTemp;
  744.         ar >> wTemp; m_nAllocPoints = wTemp;
  745.         m_points = new CPoint[m_nAllocPoints];
  746.         for (i = 0;i < m_nPoints; i++)
  747.             ar >> m_points[i];
  748.     }
  749. }
  750.  
  751. void CDrawPoly::Draw(CDC* pDC)
  752. {
  753.     ASSERT_VALID(this);
  754.  
  755.     CBrush brush;
  756.     if (!brush.CreateBrushIndirect(&m_logbrush))
  757.         return;
  758.     CPen pen;
  759.     if (!pen.CreatePenIndirect(&m_logpen))
  760.         return;
  761.  
  762.     CBrush* pOldBrush;
  763.     CPen* pOldPen;
  764.  
  765.     if (m_bBrush)
  766.         pOldBrush = pDC->SelectObject(&brush);
  767.     else
  768.         pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
  769.  
  770.     if (m_bPen)
  771.         pOldPen = pDC->SelectObject(&pen);
  772.     else
  773.         pOldPen = (CPen*)pDC->SelectStockObject(NULL_PEN);
  774.  
  775.     pDC->Polygon(m_points, m_nPoints);
  776.  
  777.     pDC->SelectObject(pOldBrush);
  778.     pDC->SelectObject(pOldPen);
  779. }
  780.  
  781. // position must be in logical coordinates
  782. void CDrawPoly::MoveTo(const CRect& position, CDrawView* pView)
  783. {
  784.     ASSERT_VALID(this);
  785.     if (position == m_position)
  786.         return;
  787.  
  788.     if (pView == NULL)
  789.         Invalidate();
  790.     else
  791.         pView->InvalObj(this);
  792.  
  793.     for (int i = 0; i < m_nPoints; i += 1)
  794.     {
  795.         m_points[i].x += position.left - m_position.left;
  796.         m_points[i].y += position.top - m_position.top;
  797.     }
  798.  
  799.     m_position = position;
  800.  
  801.     if (pView == NULL)
  802.         Invalidate();
  803.     else
  804.         pView->InvalObj(this);
  805.     m_pDocument->SetModifiedFlag();
  806. }
  807.  
  808. int CDrawPoly::GetHandleCount()
  809. {
  810.     return m_nPoints;
  811. }
  812.  
  813. CPoint CDrawPoly::GetHandle(int nHandle)
  814. {
  815.     ASSERT_VALID(this);
  816.  
  817.     ASSERT(nHandle >= 1 && nHandle <= m_nPoints);
  818.     return m_points[nHandle - 1];
  819. }
  820.  
  821. HCURSOR CDrawPoly::GetHandleCursor(int )
  822. {
  823.     return AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  824. }
  825.  
  826. // point is in logical coordinates
  827. void CDrawPoly::MoveHandleTo(int nHandle, CPoint point, CDrawView* pView)
  828. {
  829.     ASSERT_VALID(this);
  830.     ASSERT(nHandle >= 1 && nHandle <= m_nPoints);
  831.     if (m_points[nHandle - 1] == point)
  832.         return;
  833.  
  834.     m_points[nHandle - 1] = point;
  835.     RecalcBounds(pView);
  836.  
  837.     if (pView == NULL)
  838.         Invalidate();
  839.     else
  840.         pView->InvalObj(this);
  841.     m_pDocument->SetModifiedFlag();
  842. }
  843.  
  844. // rect must be in logical coordinates
  845. BOOL CDrawPoly::Intersects(const CRect& rect)
  846. {
  847.     ASSERT_VALID(this);
  848.     CRgn rgn;
  849.     rgn.CreatePolygonRgn(m_points, m_nPoints, ALTERNATE);
  850.     return rgn.RectInRegion(rect);
  851. }
  852.  
  853. CDrawObj* CDrawPoly::Clone(CDrawDoc* pDoc)
  854. {
  855.     ASSERT_VALID(this);
  856.  
  857.     CDrawPoly* pClone = new CDrawPoly(m_position);
  858.     pClone->m_bPen = m_bPen;
  859.     pClone->m_logpen = m_logpen;
  860.     pClone->m_bBrush = m_bBrush;
  861.     pClone->m_logbrush = m_logbrush;
  862.     pClone->m_points = new CPoint[m_nAllocPoints];
  863.     memcpy(pClone->m_points, m_points, sizeof(CPoint) * m_nPoints);
  864.     pClone->m_nAllocPoints = m_nAllocPoints;
  865.     pClone->m_nPoints = m_nPoints;
  866.     ASSERT_VALID(pClone);
  867.  
  868.     if (pDoc != NULL)
  869.         pDoc->Add(pClone);
  870.  
  871.     ASSERT_VALID(pClone);
  872.     return pClone;
  873. }
  874.  
  875. // point is in logical coordinates
  876. void CDrawPoly::AddPoint(const CPoint& point, CDrawView* pView)
  877. {
  878.     ASSERT_VALID(this);
  879.     if (m_nPoints == m_nAllocPoints)
  880.     {
  881.         CPoint* newPoints = new CPoint[m_nAllocPoints + 10];
  882.         if (m_points != NULL)
  883.         {
  884.             memcpy(newPoints, m_points, sizeof(CPoint) * m_nAllocPoints);
  885.             delete[] m_points;
  886.         }
  887.         m_points = newPoints;
  888.         m_nAllocPoints += 10;
  889.     }
  890.  
  891.     if (m_nPoints == 0 || m_points[m_nPoints - 1] != point)
  892.     {
  893.         m_points[m_nPoints++] = point;
  894.         if (!RecalcBounds(pView))
  895.         {
  896.             if (pView == NULL)
  897.                 Invalidate();
  898.             else
  899.                 pView->InvalObj(this);
  900.         }
  901.         m_pDocument->SetModifiedFlag();
  902.     }
  903. }
  904.  
  905. BOOL CDrawPoly::RecalcBounds(CDrawView* pView)
  906. {
  907.     ASSERT_VALID(this);
  908.  
  909.     if (m_nPoints == 0)
  910.         return FALSE;
  911.  
  912.     CRect bounds(m_points[0], CSize(0, 0));
  913.     for (int i = 1; i < m_nPoints; ++i)
  914.     {
  915.         if (m_points[i].x < bounds.left)
  916.             bounds.left = m_points[i].x;
  917.         if (m_points[i].x > bounds.right)
  918.             bounds.right = m_points[i].x;
  919.         if (m_points[i].y < bounds.top)
  920.             bounds.top = m_points[i].y;
  921.         if (m_points[i].y > bounds.bottom)
  922.             bounds.bottom = m_points[i].y;
  923.     }
  924.  
  925.     if (bounds == m_position)
  926.         return FALSE;
  927.  
  928.     if (pView == NULL)
  929.         Invalidate();
  930.     else
  931.         pView->InvalObj(this);
  932.  
  933.     m_position = bounds;
  934.  
  935.     if (pView == NULL)
  936.         Invalidate();
  937.     else
  938.         pView->InvalObj(this);
  939.  
  940.     return TRUE;
  941. }
  942.  
  943. ////////////////////////////////////////////////////////////////////////////
  944.  
  945. IMPLEMENT_SERIAL(CDrawOleObj, CDrawObj, 0)
  946.  
  947. BOOL CDrawOleObj::c_bShowItems = TRUE;
  948.  
  949. CDrawOleObj::CDrawOleObj() : m_extent(0,0)
  950. {
  951.     m_pClientItem = NULL;
  952. }
  953.  
  954. CDrawOleObj::CDrawOleObj(const CRect& position)
  955.     : CDrawObj(position), m_extent(0, 0)
  956. {
  957.     m_pClientItem = NULL;
  958. }
  959.  
  960. CDrawOleObj::~CDrawOleObj()
  961. {
  962.     if (m_pClientItem != NULL)
  963.     {
  964.         m_pClientItem->Release();
  965.         m_pClientItem = NULL;
  966.     }
  967. }
  968.  
  969. void CDrawOleObj::Remove()
  970. {
  971.     if (m_pClientItem != NULL)
  972.     {
  973.         m_pClientItem->Delete();
  974.         m_pClientItem = NULL;
  975.     }
  976.     CDrawObj::Remove();
  977. }
  978.  
  979. void CDrawOleObj::Serialize( CArchive& ar )
  980. {
  981.     ASSERT_VALID(this);
  982.  
  983.     CDrawObj::Serialize(ar);
  984.  
  985.     if (ar.IsStoring())
  986.     {
  987.         ar << m_extent;
  988.         ar << m_pClientItem;
  989.     }
  990.     else
  991.     {
  992.         ar >> m_extent;
  993.         ar >> m_pClientItem;
  994.         m_pClientItem->m_pDrawObj = this;
  995.     }
  996. }
  997.  
  998. CDrawObj* CDrawOleObj::Clone(CDrawDoc* pDoc)
  999. {
  1000.     ASSERT_VALID(this);
  1001.  
  1002.     AfxGetApp()->BeginWaitCursor();
  1003.  
  1004.     CDrawOleObj* pClone = NULL;
  1005.     CDrawItem* pItem = NULL;
  1006.     TRY
  1007.     {
  1008.         // perform a "deep copy" -- need to copy CDrawOleObj and the CDrawItem
  1009.         //  that it points to.
  1010.         CDrawOleObj* pClone = new CDrawOleObj(m_position);
  1011.         CDrawItem* pItem = new CDrawItem(m_pDocument, pClone);
  1012.         if (!pItem->CreateCloneFrom(m_pClientItem))
  1013.             AfxThrowMemoryException();
  1014.  
  1015.         pClone->m_pClientItem = pItem;
  1016.         pClone->m_bPen = m_bPen;
  1017.         pClone->m_logpen = m_logpen;
  1018.         pClone->m_bBrush = m_bBrush;
  1019.         pClone->m_logbrush = m_logbrush;
  1020.         ASSERT_VALID(pClone);
  1021.  
  1022.         if (pDoc != NULL)
  1023.             pDoc->Add(pClone);
  1024.     }
  1025.     CATCH_ALL(e)
  1026.     {
  1027.         pItem->Delete();
  1028.         pClone->m_pClientItem = NULL;
  1029.         pClone->Remove();
  1030.         AfxGetApp()->EndWaitCursor();
  1031.  
  1032.         THROW_LAST();
  1033.     }
  1034.     END_CATCH_ALL
  1035.  
  1036.     AfxGetApp()->EndWaitCursor();
  1037.     return pClone;
  1038. }
  1039.  
  1040. void CDrawOleObj::Draw(CDC* pDC)
  1041. {
  1042.     ASSERT_VALID(this);
  1043.  
  1044.     CDrawItem* pItem = m_pClientItem;
  1045.     if (pItem != NULL)
  1046.     {
  1047.         // draw the OLE item itself
  1048.         pItem->Draw(pDC, m_position);
  1049.  
  1050.         // don't draw tracker in print preview or on printer
  1051.         if (!pDC->IsPrinting())
  1052.         {
  1053.             // use a CRectTracker to draw the standard effects
  1054.             CRectTracker tracker;
  1055.             tracker.m_rect = m_position;
  1056.             pDC->LPtoDP(tracker.m_rect);
  1057.  
  1058.             if (c_bShowItems)
  1059.             {
  1060.                 // put correct border depending on item type
  1061.                 if (pItem->GetType() == OT_LINK)
  1062.                     tracker.m_nStyle |= CRectTracker::dottedLine;
  1063.                 else
  1064.                     tracker.m_nStyle |= CRectTracker::solidLine;
  1065.             }
  1066.  
  1067.             // put hatching over the item if it is currently open
  1068.             if (pItem->GetItemState() == COleClientItem::openState ||
  1069.                 pItem->GetItemState() == COleClientItem::activeUIState)
  1070.             {
  1071.                 tracker.m_nStyle |= CRectTracker::hatchInside;
  1072.             }
  1073.             tracker.Draw(pDC);
  1074.         }
  1075.     }
  1076. }
  1077.  
  1078. void CDrawOleObj::OnOpen(CDrawView* pView)
  1079. {
  1080.     AfxGetApp()->BeginWaitCursor();
  1081.     m_pClientItem->DoVerb(
  1082.         GetKeyState(VK_CONTROL) < 0 ? OLEIVERB_OPEN : OLEIVERB_PRIMARY,
  1083.         pView);
  1084.     AfxGetApp()->EndWaitCursor();
  1085. }
  1086.  
  1087. void CDrawOleObj::OnEditProperties()
  1088. {
  1089.     // using COlePropertiesDialog directly means no scaling
  1090.     COlePropertiesDialog dlg(m_pClientItem, 100, 100, NULL);
  1091.  
  1092.     dlg.DoModal();
  1093. }
  1094.  
  1095. // position is in logical
  1096. void CDrawOleObj::MoveTo(const CRect& position, CDrawView* pView)
  1097. {
  1098.     ASSERT_VALID(this);
  1099.  
  1100.     if (position == m_position)
  1101.         return;
  1102.  
  1103.     // call base class to update position
  1104.     CDrawObj::MoveTo(position, pView);
  1105.  
  1106.     // update position of in-place editing session on position change
  1107.     if (m_pClientItem->IsInPlaceActive())
  1108.         m_pClientItem->SetItemRects();
  1109. }
  1110.  
  1111. /////////////////////////////////////////////////////////////////////////////
  1112.