POLYLINE.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:26k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * POLYLINE.CPP
  3.  * Cosmo Chapter 1
  4.  *
  5.  * Implementation of the CPolyline class.
  6.  *
  7.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  8.  *
  9.  * Kraig Brockschmidt, Microsoft
  10.  * Internet  :  kraigb@microsoft.com
  11.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  12.  */
  13. #include "cosmo.h"
  14. /*
  15.  * CPolyline:CPolyline
  16.  * CPolyline::~CPolyline
  17.  *
  18.  * Constructor Parameters:
  19.  *  hInst           HINSTANCE of the application we're in.
  20.  */
  21. CPolyline::CPolyline(HINSTANCE hInst)
  22.     : CWindow(hInst)
  23.     {
  24.     m_pAdv=NULL;
  25.     m_hWnd=NULL;
  26.     return;
  27.     }
  28. CPolyline::~CPolyline(void)
  29.     {
  30.     return;
  31.     }
  32. /*
  33.  * CPolyline::Init
  34.  *
  35.  * Purpose:
  36.  *  Instantiates a polyline window within a given parent.  The
  37.  *  parent may be a main application window, could be an MDI child
  38.  *  window. We really do not care.
  39.  *
  40.  * Parameters:
  41.  *  hWndParent      HWND of the parent of this window
  42.  *  pRect           LPRECT that this window should occupy
  43.  *  dwStyle         DWORD containing the window's style flags
  44.  *  uID             UINT ID to associate with this window
  45.  *  pAdv            PCPolylineAdviseSink of the sink wanting our
  46.  *                  notifications.
  47.  *
  48.  * Return Value:
  49.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  50.  */
  51. BOOL CPolyline::Init(HWND hWndParent, LPRECT pRect, DWORD dwStyle
  52.     , UINT uID, PCPolylineAdviseSink pAdv)
  53.     {
  54.     m_hWnd=CreateWindowEx(WS_EX_NOPARENTNOTIFY, SZCLASSPOLYLINE
  55.         , SZCLASSPOLYLINE, dwStyle, pRect->left, pRect->top
  56.         , pRect->right-pRect->left, pRect->bottom-pRect->top
  57.         , hWndParent, (HMENU)uID, m_hInst, this);
  58.     if (NULL!=m_hWnd)
  59.         m_pAdv=pAdv;
  60.     return (NULL!=m_hWnd);
  61.     }
  62. /*
  63.  * CPolyline::New
  64.  *
  65.  * Purpose:
  66.  *  Cleans out and reinitializes the data to defaults.
  67.  *
  68.  * Parameters:
  69.  *  None
  70.  *
  71.  * Return Value:
  72.  *  None
  73.  */
  74. void CPolyline::New(void)
  75.     {
  76.     UINT        i;
  77.     RECT        rc;
  78.     m_pl.wVerMaj=VERSIONMAJOR;
  79.     m_pl.wVerMin=VERSIONMINOR;
  80.     //Our rectangle is the size of our window's client area.
  81.     GetClientRect(m_hWnd, &rc);
  82.     RECTTORECTS(rc, m_pl.rc);
  83.     //Clean out the POLYLINE structure and repaint the window.
  84.     for (i=0; i< CPOLYLINEPOINTS; i++)
  85.         {
  86.         m_pl.rgpt[i].x=0;
  87.         m_pl.rgpt[i].y=0;
  88.         }
  89.     m_pl.cPoints      =0;
  90.     m_pl.rgbBackground=GetSysColor(COLOR_WINDOW);
  91.     m_pl.rgbLine      =GetSysColor(COLOR_WINDOWTEXT);
  92.     m_pl.iLineStyle   =PS_SOLID;
  93.     InvalidateRect(m_hWnd, NULL, TRUE);
  94.     UpdateWindow(m_hWnd);
  95.     //Inform the advise sink of this data change.
  96.     if (NULL!=m_pAdv)
  97.         m_pAdv->OnDataChange();
  98.     return;
  99.     }
  100. /*
  101.  * CPolyline::Undo
  102.  *
  103.  * Purpose:
  104.  *  Reverses previous actions in a Polyline.
  105.  *
  106.  * Parameters:
  107.  *  None
  108.  *
  109.  * Return Value:
  110.  *  BOOL            TRUE if we can Undo more, FALSE otherwise.
  111.  */
  112. BOOL CPolyline::Undo(void)
  113.     {
  114.     //Decrement the number of active points and repaint.
  115.     if (m_pl.cPoints > 0)
  116.         {
  117.         m_pl.cPoints--;
  118.         InvalidateRect(m_hWnd, NULL, TRUE);
  119.         UpdateWindow(m_hWnd);
  120.         }
  121.     if (NULL!=m_pAdv)
  122.         m_pAdv->OnPointChange();
  123.     //Return if we can undo any more.
  124.     return (0!=m_pl.cPoints);
  125.     }
  126. /*
  127.  * CPolyline::ReadFromFile
  128.  *
  129.  * Purpose:
  130.  *  Loads our data (any known version) from a file handle returning
  131.  *  the version number of the data or an error value.
  132.  *
  133.  * Parameters:
  134.  *  pszFile         LPTSTR of the file to open.
  135.  *
  136.  * Return Value:
  137.  *  LONG            Version number or negative POLYLINE_E_* value.
  138.  */
  139. LONG CPolyline::ReadFromFile(LPTSTR pszFile)
  140.     {
  141.     OFSTRUCT        of;
  142.     HFILE           hFile;
  143.     POLYLINEDATA    pl;
  144.     UINT            cb=(UINT)-1;
  145.     UINT            cbExpect=0;
  146.     if (NULL==pszFile)
  147.         return POLYLINE_E_READFAILURE;
  148.     //OpenFileW is a member of CPolyline.
  149.     hFile=OpenFileW(pszFile, &of, OF_READ);
  150.     if (HFILE_ERROR==hFile)
  151.         return POLYLINE_E_READFAILURE;
  152.     //Read version numbers and seek back to file beginning.
  153.     cb=_lread(hFile, &pl, 2*sizeof(WORD));
  154.     _llseek(hFile, 0L, 0);
  155.     if (2*sizeof(WORD)!=cb)
  156.         {
  157.         _lclose(hFile);
  158.         return POLYLINE_E_READFAILURE;
  159.         }
  160.     /*
  161.      * For version 2.0, read the entire file.  For version 1.0 read
  162.      * the file up to CBPOLYLINEDATAVER10.  For anything else, give
  163.      * an error.
  164.      */
  165.     switch (pl.wVerMaj)
  166.         {
  167.         case VERSIONMAJOR:  //2.x
  168.             switch (pl.wVerMin)
  169.                 {
  170.                 case VERSIONMINOR:  //2.0
  171.                     cbExpect=CBPOLYLINEDATA;
  172.                     break;
  173.                 default:
  174.                     break;
  175.                 }
  176.             break;
  177.         case 1: //1.x
  178.             switch (pl.wVerMin)
  179.                 {
  180.                 case 0:  //1.0
  181.                     cbExpect=CBPOLYLINEDATA10;
  182.                     break;
  183.                 default:
  184.                     break;
  185.                 }
  186.             break;
  187.         default:
  188.             break;
  189.         }
  190.     if (0==cbExpect)
  191.         {
  192.         _lclose(hFile);
  193.         return POLYLINE_E_UNSUPPORTEDVERSION;
  194.         }
  195.     cb=_lread(hFile, &pl, cbExpect);
  196.     _lclose(hFile);
  197.     if (cbExpect!=cb)
  198.         return POLYLINE_E_READFAILURE;
  199.     /*
  200.      * If we loaded successfully, make the data current.  By using
  201.      * DataSet we centralize our version upgrading.  We size the
  202.      * polyline window to the data AND notify the document so it
  203.      * sizes to the polyline.
  204.      */
  205.     DataSet(&pl, TRUE, TRUE);
  206.     //Return what version we just loaded.
  207.     return MAKELONG(pl.wVerMin, pl.wVerMaj);
  208.     }
  209. /*
  210.  * CPolyline::WriteToFile
  211.  *
  212.  * Purpose:
  213.  *  Ignorantly writes our current data into an opened file in a
  214.  *  particular version.
  215.  *
  216.  * Parameters:
  217.  *  pszFile         LPTSTR filename in which to store the data.
  218.  *  lVer            LONG providing version number Major (HI)
  219.  *                  and Minor (Low)
  220.  *
  221.  * Return Value:
  222.  *  LONG            A POLYLINE_E_* value.
  223.  */
  224. LONG CPolyline::WriteToFile(LPTSTR pszFile, LONG lVer)
  225.     {
  226.     OFSTRUCT        of;
  227.     HFILE           hFile;
  228.     UINT            cb;
  229.     UINT            cbExpect=0;
  230.     WORD            wVerMaj=HIWORD(lVer);
  231.     WORD            wVerMin=LOWORD(lVer);
  232.     POLYLINEDATA    pl;
  233.     if (NULL==pszFile)
  234.         return POLYLINE_E_READFAILURE;
  235.     //Get a copy of our data in the version we're going to save.
  236.     DataGet(&pl, lVer);
  237.     switch (wVerMaj)
  238.         {
  239.         case VERSIONMAJOR:  //2.x
  240.             switch (wVerMin)
  241.                 {
  242.                 case VERSIONMINOR:  //2.0
  243.                     cbExpect=CBPOLYLINEDATA;
  244.                     break;
  245.                 default:
  246.                     break;
  247.                 }
  248.             break;
  249.         case 1: //1.x
  250.             switch (wVerMin)
  251.                 {
  252.                 case 0:  //1.0
  253.                     cbExpect=CBPOLYLINEDATA10;
  254.                     break;
  255.                 default:
  256.                     break;
  257.                 }
  258.             break;
  259.         default:
  260.             break;
  261.         }
  262.     if (0==cbExpect)
  263.         return POLYLINE_E_UNSUPPORTEDVERSION;
  264.     hFile=OpenFileW(pszFile, &of, OF_CREATE | OF_WRITE);
  265.     if (HFILE_ERROR==hFile)
  266.         return DOCERR_COULDNOTOPEN;
  267.     cb=_lwrite(hFile, (LPCSTR)&pl, cbExpect);
  268.     _lclose(hFile);
  269.     return (cbExpect==cb) ? POLYLINE_E_NONE
  270.         : POLYLINE_E_WRITEFAILURE;
  271.     }
  272. /*
  273.  * CPolyline::OpenFileW (Private)
  274.  *
  275.  * Purpose:
  276.  *  Under Win32, OpenFile does not take Unicode strings.  This
  277.  *  function converts a Unicode string into an ANSI string and
  278.  *  calls OpenFile.  This just maps to OpenFile without Unicode.
  279.  *
  280.  * Parameters, Return Value:
  281.  *  Same as OpenFile.
  282.  */
  283. HFILE CPolyline::OpenFileW(LPTSTR pszFile, LPOFSTRUCT pof
  284.     , UINT uFlags)
  285.     {
  286.    #ifdef UNICODE
  287.     CHAR        szTemp[CCHPATHMAX];
  288.     UNICODETOANSI(pszFile, szTemp, CCHPATHMAX);
  289.     return OpenFile(szTemp, pof, uFlags);
  290.    #else
  291.     return OpenFile(pszFile, pof, uFlags);
  292.    #endif
  293.     }
  294. /*
  295.  * CPolyline::DataSet
  296.  *
  297.  * Purpose:
  298.  *  Sets the current data in this Polyline to a given structure.
  299.  *
  300.  * Parameters:
  301.  *  ppl             PPOLYLINEDATA to initialize to.
  302.  *  fSizeToData     BOOL indicating if we're to size to the data or
  303.  *                  scale it.
  304.  *  fNotify         BOOL indicating if we're to send an advise on
  305.  *                  this change.
  306.  *
  307.  * Return Value:
  308.  *  LONG            A POLYLINE_E_* value.
  309.  */
  310. LONG CPolyline::DataSet(PPOLYLINEDATA ppl, BOOL fSizeToData
  311.     , BOOL fNotify)
  312.     {
  313.     RECTS       rcs;
  314.     RECT        rc;
  315.     UINT        i;
  316.     /*
  317.      * Copy the structure in ppl and repaint to reflect the new
  318.      * point set.  Note that unlike the RectSet message, we do no
  319.      * scaling, assuming that the rect in the structure is
  320.      * appropriate for the data.
  321.      */
  322.     if (NULL==ppl)
  323.         return POLYLINE_E_INVALIDPOINTER;
  324.     //Preserve the old rectangle
  325.     rcs=m_pl.rc;
  326.     /*
  327.      * For version 2.0 we perform a straight copy.  For version
  328.      * 1.0 we copy the 1.0 structure and fill in defaults for
  329.      * the 2.0 additions.
  330.      */
  331.     switch (ppl->wVerMaj)
  332.         {
  333.         case VERSIONMAJOR:          //2.x
  334.             switch (ppl->wVerMin)
  335.                 {
  336.                 case VERSIONMINOR:  //2.0
  337.                     m_pl=*ppl;
  338.                     break;
  339.                 default:
  340.                     return POLYLINE_E_UNSUPPORTEDVERSION;
  341.                 }
  342.             break;
  343.         case 1:                     //1.x
  344.             switch (ppl->wVerMin)
  345.                 {
  346.                 case 0:             //1.0
  347.                     *((PPOLYLINEDATA10)&m_pl)=
  348.                         *((PPOLYLINEDATA10)ppl);
  349.                     /*
  350.                      * Update this structure to 2.0.  Note that we
  351.                      * assume whoever loaded us to save the loaded
  352.                      * version so it can later ask what version
  353.                      * the user wants to save.
  354.                      */
  355.                     m_pl.wVerMaj=VERSIONMAJOR;
  356.                     m_pl.wVerMin=VERSIONMINOR;
  357.                     /*
  358.                      * Version 1.0 stored rc in parent coordinates.
  359.                      * We need those now in our client coodinates.
  360.                      */
  361.                     RECTSTORECT(m_pl.rc, rc);
  362.                     OffsetRect(&rc, -m_pl.rc.left, -m_pl.rc.top);
  363.                     /*
  364.                      * 1.0 data had points relative to size of the
  365.                      * rectangle.  We need to scale these to 0-32767
  366.                      * independent of the rectangle for the version
  367.                      * upgrade.
  368.                      */
  369.                     for (i=0; i < m_pl.cPoints; i++)
  370.                         PointScale(&rc, &m_pl.rgpt[i], FALSE);
  371.                     RECTTORECTS(rc, m_pl.rc);
  372.                     //New 2.0 features
  373.                     m_pl.rgbBackground=GetSysColor(COLOR_WINDOW);
  374.                     m_pl.rgbLine=GetSysColor(COLOR_WINDOWTEXT);
  375.                     m_pl.iLineStyle=PS_SOLID;
  376.                     break;
  377.                 default:
  378.                     return POLYLINE_E_UNSUPPORTEDVERSION;
  379.                 }
  380.             break;
  381.         default:
  382.             return POLYLINE_E_UNSUPPORTEDVERSION;
  383.         }
  384.     //Inform our parent of the data change
  385.     if (NULL!=m_pAdv)
  386.         m_pAdv->OnDataChange();
  387.     /*
  388.      * If we're scaling the window to fit the data, then use
  389.      * RectSet passing our current rectangle as the new one.
  390.      * That makes sure that the data won't change but that the
  391.      * window is resized.
  392.      */
  393.     if (fSizeToData)
  394.         {
  395.         POINT       pt;
  396.         /*
  397.          * Get our offset in the parent window so we can RectSet
  398.          * to the right place since RectSet expects rectangle in
  399.          * parent coordinates and we get it in client coordinates.
  400.          */
  401.         GetWindowRect(m_hWnd, &rc);
  402.         pt.x=rc.left;
  403.         pt.y=rc.top;
  404.         ScreenToClient(GetParent(m_hWnd), &pt);
  405.         RECTSTORECT(m_pl.rc, rc);
  406.         OffsetRect(&rc, pt.x, pt.y);
  407.         //This will also cause a repaint.
  408.         RectSet(&rc, fNotify);
  409.         }
  410.     else
  411.         {
  412.         //Make sure we're updated.
  413.         InvalidateRect(m_hWnd, NULL, TRUE);
  414.         UpdateWindow(m_hWnd);
  415.         }
  416.     return POLYLINE_E_NONE;
  417.     }
  418. /*
  419.  * CPolyline::DataGet
  420.  *
  421.  * Purpose:
  422.  *  Retrieves the Polyline's current data.
  423.  *
  424.  * Parameters:
  425.  *  ppl             PPOLYLINEDATA into which we copy the data.
  426.  *  lVer            LONG version of the data to retrieve.  Use
  427.  *                  VERSIONCURRENT to retrieve the most current.
  428.  *
  429.  * Return Value:
  430.  *  LONG            A POLYLINE_E_* value
  431.  */
  432. LONG CPolyline::DataGet(PPOLYLINEDATA ppl, LONG lVer)
  433.     {
  434.     UINT        i;
  435.     RECT        rc;
  436.     //Retieve the current version
  437.     if (lVer==MAKELONG(VERSIONMINOR, VERSIONMAJOR)
  438.         || VERSIONCURRENT==lVer)
  439.         {
  440.         *ppl=m_pl;
  441.         return POLYLINE_E_NONE;
  442.         }
  443.     //Check for versions we support, 1.x
  444.     if (HIWORD(lVer)!=1)
  445.         return POLYLINE_E_UNSUPPORTEDVERSION;
  446.     if (LOWORD(lVer)==0)    //Check for 1.0
  447.         {
  448.         //Do 2.0 to 1.0 conversion
  449.         *((PPOLYLINEDATA10)ppl)=*((PPOLYLINEDATA10)&m_pl);
  450.         RECTSTORECT(ppl->rc, rc);
  451.         //Get the parent coordinates of our rectangle
  452.         if (!IsWindow(m_hWnd))
  453.             OffsetRect(&rc, 8, 8); //This is always the offset.
  454.         else
  455.             RectGet(&rc);
  456.         /*
  457.          * 1.0 data has points relative to size of the rectangle.
  458.          * We need to scale these from 0-32767 so we have the
  459.          * right values.
  460.          */
  461.         for (i=0; i < ppl->cPoints; i++)
  462.             PointScale(&rc, &ppl->rgpt[i], TRUE);
  463.         RECTTORECTS(rc, ppl->rc);
  464.         //Insure old version numbers.
  465.         ppl->wVerMaj=1;
  466.         ppl->wVerMin=0;
  467.         ((PPOLYLINEDATA10)ppl)->fDrawEntire=TRUE;
  468.         return POLYLINE_E_NONE;
  469.         }
  470.     return POLYLINE_E_UNSUPPORTEDVERSION;
  471.     }
  472. /*
  473.  * CPolyline::DataSetMem
  474.  *
  475.  * Purpose:
  476.  *  Sets the Polyline's data using a global memory handle
  477.  *  instead of a pointer.
  478.  *
  479.  * Parameters:
  480.  *  hMem            HGLOBAL containing the data.
  481.  *  fFree           BOOL indicating if we're to free the data.
  482.  *                  The memory will be freed regardless of any
  483.  *                  error returned from here.
  484.  *  fSizeToData     BOOL indicating if we're to size to the data
  485.  *                  or scale it.
  486.  *  fNotify         BOOL indicating if we're to send an advise
  487.  *                  on this change.
  488.  *
  489.  * Return Value:
  490.  *  LONG            A POLYLINE_E_* value.
  491.  */
  492. LONG CPolyline::DataSetMem(HGLOBAL hMem, BOOL fFree
  493.     , BOOL fSizeToData, BOOL fNotify)
  494.     {
  495.     PPOLYLINEDATA   ppl;
  496.     LONG            lRet=POLYLINE_E_INVALIDPOINTER;
  497.     if (NULL!=hMem)
  498.         {
  499.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  500.         lRet=DataSet(ppl, fSizeToData, fNotify);
  501.         GlobalUnlock(hMem);
  502.         if (fFree)
  503.             GlobalFree(hMem);
  504.         }
  505.     return lRet;
  506.     }
  507. /*
  508.  * CPolyline::DataGetMem
  509.  *
  510.  * Purpose:
  511.  *  Retrieves the Polyline's data in a global memory handle.
  512.  *
  513.  * Parameters:
  514.  *  lVer            LONG version of data to retrieve.
  515.  *  phMem           HGLOBAL * in which to store the handle.
  516.  *
  517.  * Return Value:
  518.  *  LONG            A POLYLINE_E_* value.
  519.  */
  520. LONG CPolyline::DataGetMem(LONG lVer, HGLOBAL *phMem)
  521.     {
  522.     HGLOBAL         hMem;
  523.     PPOLYLINEDATA   ppl;
  524.     LONG            lRet;
  525.     if (NULL==phMem)
  526.         return POLYLINE_E_INVALIDPOINTER;
  527.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  528.         , CBPOLYLINEDATA);
  529.     if (NULL!=hMem)
  530.         {
  531.         ppl=(PPOLYLINEDATA)GlobalLock(hMem);
  532.         lRet=DataGet(ppl, lVer);
  533.         GlobalUnlock(hMem);
  534.         if (POLYLINE_E_NONE!=lRet)
  535.             {
  536.             GlobalFree(hMem);
  537.             hMem=NULL;
  538.             }
  539.         }
  540.     *phMem=hMem;
  541.     return lRet;
  542.     }
  543. /*
  544.  * CPolyline::RectGet
  545.  *
  546.  * Purpose:
  547.  *  Returns the rectangle of the Polyline in parent coordinates.
  548.  *
  549.  * Parameters:
  550.  *  pRect           LPRECT in which to return the rectangle.
  551.  *
  552.  * Return Value:
  553.  *  None
  554.  */
  555. void CPolyline::RectGet(LPRECT pRect)
  556.     {
  557.     RECT        rc;
  558.     POINT       pt;
  559.     //Retrieve the size of our rectangle in parent coordinates.
  560.     GetWindowRect(m_hWnd, &rc);
  561.     pt.x=rc.left;
  562.     pt.y=rc.top;
  563.     ScreenToClient(GetParent(m_hWnd), &pt);
  564.     SetRect(pRect, pt.x, pt.y, pt.x+(rc.right-rc.left)
  565.         , pt.y+(rc.bottom-rc.top));
  566.     return;
  567.     }
  568. /*
  569.  * CPolyline::SizeGet
  570.  *
  571.  * Purpose:
  572.  *  Retrieves the size of the Polyline in parent coordinates.
  573.  *
  574.  * Parameters:
  575.  *  pRect           LPRECT in which to return the size.  The right
  576.  *                  and bottom fields will contain the dimensions.
  577.  *
  578.  * Return Value:
  579.  *  None
  580.  */
  581. void CPolyline::SizeGet(LPRECT pRect)
  582.     {
  583.     RectGet(pRect);
  584.     return;
  585.     }
  586. /*
  587.  * CPolyline::RectSet
  588.  *
  589.  * Purpose:
  590.  *  Sets a new rectangle for the Polyline which sizes to fit.
  591.  *
  592.  * Parameters:
  593.  *  pRect           LPRECT containing the new rectangle.
  594.  *  fNotify         BOOL indicating if we're to notify anyone of
  595.  *                  the change.
  596.  *
  597.  * Return Value:
  598.  *  None
  599.  */
  600. void CPolyline::RectSet(LPRECT pRect, BOOL fNotify)
  601.     {
  602.     UINT        cx, cy;
  603.     RECT        rc;
  604.     //Scale the points from our current size to the new size
  605.     cx=pRect->right-pRect->left;
  606.     cy=pRect->bottom-pRect->top;
  607.     SetWindowPos(m_hWnd, NULL, pRect->left, pRect->top
  608.         , cx, cy, SWP_NOZORDER);
  609.     SetRect(&rc, 0, 0, cx, cy);
  610.     RECTTORECTS(rc, m_pl.rc);
  611.     if (fNotify && NULL!=m_pAdv)
  612.         m_pAdv->OnSizeChange();
  613.     InvalidateRect(m_hWnd, NULL, TRUE);
  614.     return;
  615.     }
  616. /*
  617.  * CPolyline::SizeSet
  618.  *
  619.  * Purpose:
  620.  *  Sets a new size for the Polyline which sizes to fit.
  621.  *
  622.  * Parameters:
  623.  *  pRect           LPRECT containing the new rectangle.
  624.  *  fNotify         BOOL indicating if we're to notify anyone of
  625.  *                  the change.
  626.  *
  627.  * Return Value:
  628.  *  None
  629.  */
  630. void CPolyline::SizeSet(LPRECT pRect, BOOL fNotify)
  631.     {
  632.     UINT        cx, cy;
  633.     //Scale the points from our current size to the new size
  634.     cx=pRect->right-pRect->left;
  635.     cy=pRect->bottom-pRect->top;
  636.     SetWindowPos(m_hWnd, NULL, 0, 0, (UINT)cx, (UINT)cy
  637.         , SWP_NOMOVE | SWP_NOZORDER);
  638.     if (fNotify && NULL!=m_pAdv)
  639.         m_pAdv->OnSizeChange();
  640.     InvalidateRect(m_hWnd, NULL, TRUE);
  641.     return;
  642.     }
  643. /*
  644.  * CPolyline::ColorSet
  645.  *
  646.  * Purpose:
  647.  *  Changes for background or line color in the Polyline
  648.  *
  649.  * Parameters:
  650.  *  iColor          UINT index of the color to change.
  651.  *  cr              COLORREF new color to use.
  652.  *
  653.  * Return Value:
  654.  *  COLORREF        Previous color for the index iColor.
  655.  */
  656. COLORREF CPolyline::ColorSet(UINT iColor, COLORREF cr)
  657.     {
  658.     COLORREF    crRet;
  659.     switch (iColor)
  660.         {
  661.         case POLYLINECOLOR_BACKGROUND:
  662.             crRet=m_pl.rgbBackground;
  663.             m_pl.rgbBackground=cr;
  664.             break;
  665.         case POLYLINECOLOR_LINE:
  666.             crRet=m_pl.rgbLine;
  667.             m_pl.rgbLine=cr;
  668.             break;
  669.         }
  670.     //If the color changed, repaint
  671.     if (crRet!=cr)
  672.         {
  673.         if (NULL!=m_pAdv)
  674.             m_pAdv->OnColorChange();
  675.         InvalidateRect(m_hWnd, NULL, TRUE);
  676.         UpdateWindow(m_hWnd);
  677.         }
  678.     return crRet;
  679.     }
  680. /*
  681.  * CPolyline::ColorGet
  682.  *
  683.  * Purpose:
  684.  *  Retrieves one of the colors currently in use by the Polyline.
  685.  *
  686.  * Parameters:
  687.  *  iColor          UINT identifying the color of interest.
  688.  *
  689.  * Return Value:
  690.  *  COLORREF        Current color for iColor.
  691.  */
  692. COLORREF CPolyline::ColorGet(UINT iColor)
  693.     {
  694.     COLORREF    crRet;
  695.     crRet=(POLYLINECOLOR_BACKGROUND==iColor)
  696.         ? m_pl.rgbBackground : m_pl.rgbLine;
  697.     return crRet;
  698.     }
  699. /*
  700.  * CPolyline::LineStyleSet
  701.  *
  702.  * Purpose:
  703.  *  Changes the line style in use by the Polyline
  704.  *
  705.  * Parameters:
  706.  *  iStyle          UINT style of the line to use.
  707.  *
  708.  * Return Value:
  709.  *  UINT            Previous style.
  710.  */
  711. UINT CPolyline::LineStyleSet(UINT iStyle)
  712.     {
  713.     UINT        uRet=(UINT)m_pl.iLineStyle;
  714.     //Validate the line style
  715.     if (PS_SOLID==iStyle || PS_DASH==iStyle || PS_DOT==iStyle
  716.         || PS_DASHDOT==iStyle || PS_DASHDOTDOT==iStyle)
  717.         {
  718.         m_pl.iLineStyle=iStyle;
  719.         if (uRet!=(UINT)m_pl.iLineStyle)
  720.             {
  721.             if (NULL!=m_pAdv)
  722.                 m_pAdv->OnLineStyleChange();
  723.             InvalidateRect(m_hWnd, NULL, TRUE);
  724.             UpdateWindow(m_hWnd);
  725.             }
  726.         }
  727.     return uRet;
  728.     }
  729. /*
  730.  * CPolyline::LineStyleGet
  731.  *
  732.  * Purpose:
  733.  *  Retrieves the current line style in use in the Polyline
  734.  *
  735.  * Parameters:
  736.  *  None
  737.  *
  738.  * Return Value:
  739.  *  UINT            Current line style.
  740.  */
  741. UINT CPolyline::LineStyleGet(void)
  742.     {
  743.     return m_pl.iLineStyle;
  744.     }
  745. /*
  746.  * CPolyline::RenderBitmap
  747.  *
  748.  * Purpose:
  749.  *  Creates a bitmap image of the current Polyline.
  750.  *
  751.  * Parameters:
  752.  *  None
  753.  *
  754.  * Return Value:
  755.  *  HBITMAP         Handle to the newly rendered bitmap.
  756.  */
  757. HBITMAP CPolyline::RenderBitmap(void)
  758.     {
  759.     HDC         hDC;
  760.     HDC         hMemDC;
  761.     HBITMAP     hBmp;
  762.     RECT        rc;
  763.     HGDIOBJ     hObj;
  764.     //Render a bitmap the size of the current rectangle.
  765.     hDC=GetDC(m_hWnd);
  766.     hMemDC=CreateCompatibleDC(hDC);
  767.     GetClientRect(m_hWnd, &rc);
  768.     hBmp=CreateCompatibleBitmap(hDC, rc.right, rc.bottom);
  769.     if (NULL!=hBmp)
  770.         {
  771.         //Draw the POLYLINEDATA into the bitmap.
  772.         hObj=SelectObject(hMemDC, hBmp);
  773.         Draw(hMemDC, FALSE, TRUE);
  774.         SelectObject(hMemDC, hObj);
  775.         }
  776.     DeleteDC(hMemDC);
  777.     ReleaseDC(m_hWnd, hDC);
  778.     return hBmp;
  779.     }
  780. /*
  781.  * CPolyline::RenderMetafile
  782.  *
  783.  * Purpose:
  784.  *  Renders the current image of the Polyline into a metafile.
  785.  *
  786.  * Parameters:
  787.  *  None
  788.  *
  789.  * Return Value:
  790.  *  HMETAFILE       Handle to the newly created metafile.
  791.  */
  792. HMETAFILE CPolyline::RenderMetafile(void)
  793.     {
  794.     HDC         hDC;
  795.     HMETAFILE   hMF;
  796.     RECT        rc;
  797.     //Create a memory metafile and return its handle.
  798.     hDC=(HDC)CreateMetaFile(NULL);
  799.     hMF=NULL;
  800.     if (NULL!=hDC)
  801.         {
  802.         /*
  803.          * This is absolutely essential to the metafile so it
  804.          * can be scaled in the clipboard and any destination
  805.          * application.
  806.          */
  807.         SetMapMode(hDC, MM_ANISOTROPIC);
  808.         GetClientRect(m_hWnd, &rc);
  809.         SetWindowOrgEx(hDC, 0, 0, NULL);
  810.         SetWindowExtEx(hDC, rc.right, rc.bottom, NULL);
  811.         Draw(hDC, TRUE, TRUE);
  812.         hMF=CloseMetaFile(hDC);
  813.         }
  814.     return hMF;
  815.     }
  816. /*
  817.  * CPolyline::RenderMetafilePict
  818.  *
  819.  * Purpose:
  820.  *  Renders the current Polyline into a METAFILEPICT structure in
  821.  *  global memory.
  822.  *
  823.  * Parameters:
  824.  *  None
  825.  *
  826.  * Return Value:
  827.  *  HGLOBAL         Memory containing the METAFILEPICT structure.
  828.  */
  829. HGLOBAL CPolyline::RenderMetafilePict(void)
  830.     {
  831.     HGLOBAL         hMem;
  832.     HMETAFILE       hMF;
  833.     LPMETAFILEPICT  pMF;
  834.     RECT            rc;
  835.     //Get the metafile
  836.     hMF=RenderMetafile();
  837.     if (NULL==hMF)
  838.         return NULL;
  839.     //Allocate the METAFILEPICT structure.
  840.     hMem=GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE
  841.         , sizeof(METAFILEPICT));
  842.     if (NULL==hMem)
  843.         {
  844.         DeleteMetaFile(hMF);
  845.         return NULL;
  846.         }
  847.     /*
  848.      * Global lock only fails in PMODE if the selector is invalid
  849.      * (like it was discarded) or references a 0 length segment,
  850.      * neither of which can happen here.
  851.      */
  852.     pMF=(LPMETAFILEPICT)GlobalLock(hMem);
  853.     pMF->hMF=hMF;
  854.     pMF->mm=MM_ANISOTROPIC;
  855.     //Insert the extents in MM_HIMETRIC units.
  856.     GetClientRect(m_hWnd, &rc);
  857.     RectConvertMappings(&rc, FALSE);
  858.     pMF->xExt=rc.right;
  859.     pMF->yExt=rc.bottom;
  860.     GlobalUnlock(hMem);
  861.     return hMem;
  862.     }
  863. /*
  864.  * CPolyline::RectConvertMappings
  865.  *
  866.  * Purpose:
  867.  *  Converts the contents of a rectangle from device (MM_TEXT) or
  868.  *  HIMETRIC to the other.
  869.  *
  870.  * Parameters:
  871.  *  pRect           LPRECT containing the rectangle to convert.
  872.  *  fToDevice       BOOL TRUE to convert from HIMETRIC to device,
  873.  *                  FALSE to convert device to HIMETRIC.
  874.  *
  875.  * Return Value:
  876.  *  None
  877.  */
  878. void CPolyline::RectConvertMappings(LPRECT pRect, BOOL fToDevice)
  879.     {
  880.     HDC      hDC;
  881.     int      iLpx, iLpy;
  882.     if (NULL==pRect)
  883.         return;
  884.     hDC=GetDC(NULL);
  885.     iLpx=GetDeviceCaps(hDC, LOGPIXELSX);
  886.     iLpy=GetDeviceCaps(hDC, LOGPIXELSY);
  887.     ReleaseDC(NULL, hDC);
  888.     if (fToDevice)
  889.         {
  890.         pRect->left=MulDiv(iLpx, pRect->left, HIMETRIC_PER_INCH);
  891.         pRect->top =MulDiv(iLpy, pRect->top , HIMETRIC_PER_INCH);
  892.         pRect->right=MulDiv(iLpx, pRect->right,  HIMETRIC_PER_INCH);
  893.         pRect->bottom=MulDiv(iLpy, pRect->bottom,HIMETRIC_PER_INCH);
  894.        #ifdef NEVER
  895.         /*
  896.          * In this conversion we may get situations where the top
  897.          * coordinate is larger than the bottom, which messes us up.
  898.          */
  899.         if (pRect->bottom < pRect->top)
  900.             {
  901.             iLpy=pRect->top;
  902.             pRect->top=pRect->bottom;
  903.             pRect->bottom=iLpy;
  904.             }
  905.        #endif
  906.         }
  907.     else
  908.         {
  909.         pRect->left=MulDiv(pRect->left, HIMETRIC_PER_INCH, iLpx);
  910.         pRect->top =MulDiv(pRect->top , HIMETRIC_PER_INCH, iLpy);
  911.         pRect->right =MulDiv(pRect->right, HIMETRIC_PER_INCH, iLpx);
  912.         pRect->bottom=MulDiv(pRect->bottom,HIMETRIC_PER_INCH, iLpy);
  913.         }
  914.     return;
  915.     }