home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap01 / cosmo / polyline.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-03  |  26.1 KB  |  1,214 lines

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