home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk12 / clipview / edpline / edpline.c next >
Encoding:
C/C++ Source or Header  |  1990-07-05  |  21.8 KB  |  1,019 lines

  1. /*
  2.     edpline.c -- polyline editor, for practice in mouse handling
  3.     Created by Microsoft Corporation, 1989
  4. */
  5. #define INCL_DOSMEMMGR
  6. #define INCL_WINWINDOWMGR
  7. #define INCL_WINMESSAGEMGR
  8. #define INCL_WINSWITCHLIST
  9. #define INCL_WINDIALOGS
  10. #define INCL_GPIBITMAPS
  11. #define INCL_GPIPRIMITIVES
  12. #define    INCL_GPITRANSFORMS
  13. #define INCL_WINMENUS
  14. #define    INCL_WININPUT
  15. #define    INCL_WINFRAMEMGR
  16. #define    INCL_WINCLIPBOARD
  17. #include <os2.h>
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21.  
  22. #include "edpline.h"
  23.  
  24.  
  25.  
  26. #define    abs(x)            (((x) > 0) ? (x) : -(x))
  27. #define PRIM_POLYLINE        0x0001
  28. #define PRIM_POLYFILLET     0x0002
  29. #define PRIM_POLYSPLINE     0x0004
  30. #define PRIM_POINTARC        0x0008
  31.  
  32.  
  33. /************************************************************************
  34. *
  35. *   Function declarations
  36. *
  37. ************************************************************************/
  38.  
  39. /* Private functions */
  40.  
  41. VOID   cdecl main(VOID);
  42. BOOL   InitGlobals(VOID);
  43. BOOL   InitApp(VOID);
  44. VOID   Close(HWND);
  45. VOID   Command(HWND, USHORT);
  46. VOID   Paint(HPS, BOOL);
  47. VOID   MouseMove(HWND, MPARAM);
  48. VOID   ButtonUp(HWND, USHORT);
  49. VOID   ButtonDown(HWND, USHORT, MPARAM);
  50. USHORT IsPtInList(PPOINTL);
  51. USHORT AddPtToList(PPOINTL);
  52. BOOL   IsPtCloseToLine(PPOINTL, PPOINTL, PPOINTL);
  53. VOID   DrawPrimitive(HPS, USHORT);
  54. VOID   DrawPolyLine(HPS);
  55. VOID   DrawPolyFillet(HPS);
  56. VOID   DrawPolySpline(HPS);
  57. VOID   DrawPointArc(HPS);
  58. VOID   DrawControlPoints(HPS, LONG, PPOINTL);
  59. VOID   MyMessageBox(HWND, PSZ);
  60. VOID   SwapLong(PLONG, PLONG);
  61.  
  62. /* Exported functions */
  63.  
  64. ULONG    CALLBACK WndProc(HWND, USHORT, MPARAM, MPARAM);
  65. MRESULT CALLBACK AboutDlgProc(HWND, USHORT, MPARAM, MPARAM);
  66.  
  67.  
  68.  
  69. /************************************************************************
  70. *
  71. *   Global Variables
  72. *
  73. ************************************************************************/
  74.  
  75. typedef struct
  76. {
  77.     HAB  hab;
  78.     HMQ  hMsgQ;
  79.     HWND hwndFrame;
  80.     HWND hwnd;
  81.  
  82.     ULONG   flPrim;
  83.     BOOL    fDisplayControlPoints;
  84.     LONG    cptl;
  85.     PPOINTL pptl;
  86.  
  87.     USHORT  usPtGrabbed;
  88.     BOOL    fDragging;
  89.  
  90.     ULONG   ulHitPrecision;
  91.  
  92.     HPS     hpsMetafile;
  93.     HDC     hdcMetafile;
  94.     ULONG   hItem;
  95.     SIZEL   sizlPage;
  96.     DEVOPENSTRUC dop;
  97.  
  98. } GLOBALDATA;
  99. GLOBALDATA global;
  100.  
  101.  
  102. /************************************************************************
  103. *
  104. *   main
  105. *
  106. *   WinInitialize resizes our ring 2 stack, among other things, so
  107. *   we won't GP fault trying to do graphics.  WinCreateMsgQueue defines
  108. *   us as a REAL PM app. (as well as the WINDOWAPI statement in the .DEF
  109. *   file...)   Call a sub to register our window class and create a window.
  110. *   Loop over messages.  Exit cleanly.
  111. *
  112. ************************************************************************/
  113.  
  114. VOID cdecl
  115. main()
  116. {
  117.     QMSG qMsg;
  118.     int iRet = 0;
  119.  
  120.  
  121.     global.hab     = WinInitialize(0);
  122.     global.hMsgQ = WinCreateMsgQueue(global.hab, 0);
  123.  
  124.     if (InitApp())
  125.     while (WinGetMsg( global.hab, (PQMSG)&qMsg, (HWND)NULL, 0, 0 ))
  126.         WinDispatchMsg( global.hab, (PQMSG)&qMsg );
  127.     else
  128.     iRet = -1;
  129.  
  130.     WinDestroyWindow( global.hwndFrame );
  131.     WinDestroyMsgQueue( global.hMsgQ );
  132.     WinTerminate( global.hab );
  133.     DosExit(EXIT_PROCESS, iRet);
  134. }
  135.  
  136.  
  137.  
  138.  
  139. /****************************************************************************
  140. *
  141. *   InitGlobals
  142. *
  143. *   Initialize global variables.
  144. *
  145. ****************************************************************************/
  146.  
  147. BOOL
  148. InitGlobals()
  149. {
  150.     global.flPrim = PRIM_POLYLINE;
  151.     global.fDisplayControlPoints = TRUE;
  152.  
  153.     global.cptl = 0L;
  154.     global.pptl = NULL;
  155.     if (DosAllocSeg(CPTLMAX * sizeof(POINTL),
  156.            ((PUSHORT)&global.pptl)+1, 0))
  157.     return FALSE;
  158.  
  159.     global.usPtGrabbed = -1;
  160.     global.fDragging = FALSE;
  161.     global.ulHitPrecision = 0L;
  162.  
  163.     return TRUE;
  164. }
  165.  
  166.  
  167.  
  168.  
  169. /****************************************************************************
  170. *
  171. *   InitApp
  172. *
  173. *   Register application window class and creates standard window.
  174. *
  175. ****************************************************************************/
  176.  
  177. #define INIT_MENU_ITEM(val, var)     \
  178.     TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var))
  179.  
  180. BOOL
  181. InitApp()
  182. {
  183.     char szTitle[24];
  184.     ULONG ctldata;
  185.     PID pid;
  186.     TID tid;
  187.     HSWITCH hsw;
  188.     static SWCNTRL swctl = { 0, 0, 0, 0, 0, SWL_VISIBLE,
  189.                  SWL_JUMPABLE, "Edit Polyline", 0 };
  190.  
  191.     if (!InitGlobals())
  192.     return FALSE;
  193.  
  194.  
  195.     /*  Register Application Window Class  */
  196.  
  197.     WinLoadString( global.hab, (HMODULE) NULL, IDS_TITLE, sizeof(szTitle), (PCH)szTitle );
  198.     if ( !WinRegisterClass( global.hab, (PCH)szTitle, (PFNWP)WndProc,
  199.         CS_SIZEREDRAW, 0 ))
  200.     return FALSE;
  201.  
  202.  
  203.  
  204.     /* Create a window instance of class "PolyLine Editor" */
  205.  
  206.     ctldata = FCF_STANDARD &
  207.      ~(ULONG)(FCF_ICON | FCF_TASKLIST);
  208.  
  209.     if (global.hwndFrame = WinCreateStdWindow(
  210.     HWND_DESKTOP,           /* specify desktop as parent window        */
  211.     WS_VISIBLE,           /* window styles                */
  212.     &ctldata,           /* frame creation flags            */
  213.     (PCH)szTitle,           /* window class name             */
  214.     (PCH)szTitle,           /* name appearing in window caption        */
  215.     0L,               /*                        */
  216.     (HMODULE)NULL,           /* use current executable module id        */
  217.     IDR_EDPLINE,           /* menu id                    */
  218.     (HWND FAR *)&global.hwnd   /* window handle                */
  219.     ))
  220.     {
  221.     INIT_MENU_ITEM(IDM_CTLPOINTS, global.fDisplayControlPoints);
  222.  
  223.     if (global.flPrim & PRIM_POLYLINE)
  224.         CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYLINE);
  225.     if (global.flPrim & PRIM_POLYFILLET)
  226.         CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYFILLET);
  227.     if (global.flPrim & PRIM_POLYSPLINE)
  228.         CHECK_MENU_ITEM(global.hwndFrame, IDM_POLYSPLINE);
  229.     if (global.flPrim & PRIM_POINTARC)
  230.         CHECK_MENU_ITEM(global.hwndFrame, IDM_POINTARC);
  231.  
  232.  
  233.     /* Add ourselves to the switch list. */
  234.  
  235.     WinQueryWindowProcess(global.hwndFrame, &pid, &tid);
  236.     swctl.hwnd    = global.hwndFrame;
  237.     swctl.idProcess = pid;
  238.     hsw = WinAddSwitchEntry(&swctl);
  239.  
  240.     return TRUE;
  241.     }
  242.     return FALSE;
  243. }
  244.  
  245.  
  246.  
  247.  
  248. /************************************************************************
  249. *
  250. *   WndProc
  251. *
  252. *   Process messages for the window class.
  253. *
  254. ************************************************************************/
  255.  
  256. ULONG CALLBACK
  257. WndProc( hwnd, usMsg, mp1, mp2 )
  258. HWND   hwnd;
  259. USHORT usMsg;
  260. MPARAM  mp1;
  261. MPARAM  mp2;
  262. {
  263.     HPS   hps;
  264.  
  265.     switch (usMsg)
  266.     {
  267.     case WM_CLOSE:
  268.     Close(hwnd);
  269.     break;
  270.  
  271.     case WM_COMMAND:
  272.     Command(hwnd, LOUSHORT(mp1));
  273.     break;
  274.  
  275.     case WM_PAINT:
  276.     hps = WinBeginPaint(global.hwnd, NULL, NULL);
  277.  
  278.     if (global.ulHitPrecision == 0L)
  279.     {
  280.         HDC hdc;
  281.         LONG cx;
  282.  
  283.         if (hdc = WinQueryWindowDC(global.hwnd)) {
  284.         DevQueryCaps(hdc, CAPS_MARKER_WIDTH,  1L,  &cx);
  285.         global.ulHitPrecision = (cx >> 17) + 1L;
  286.         } else {
  287.         global.ulHitPrecision = 6L;
  288.         }
  289.     }
  290.     Paint(hps, TRUE);
  291.     WinEndPaint(hps);
  292.     break;
  293.  
  294.     case WM_BUTTON1DOWN:
  295.     case WM_BUTTON2DOWN:
  296.     ButtonDown(hwnd, usMsg, mp1);
  297.     break;
  298.  
  299.     case WM_BUTTON1UP:
  300.     case WM_BUTTON2UP:
  301.     ButtonUp(hwnd, usMsg);
  302.     break;
  303.  
  304.     case WM_MOUSEMOVE:
  305.     MouseMove(hwnd, mp1);
  306.     return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  307.     break;
  308.  
  309.     default:
  310.     return( (ULONG)WinDefWindowProc(hwnd, usMsg, mp1, mp2));
  311.     break;
  312.     }
  313.  
  314.     return FALSE;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. /************************************************************************
  321. *
  322. *   MouseMove
  323. *
  324. ************************************************************************/
  325.  
  326. VOID
  327. MouseMove(hwnd, mp1)
  328. HWND hwnd;
  329. MPARAM mp1;
  330. {
  331.     POINTL ptl;
  332.     HPS hps;
  333.  
  334.     if (hwnd == global.hwnd)
  335.     if (global.fDragging)
  336.     {
  337.         ptl.x = (LONG) LOUSHORT(mp1);
  338.         ptl.y = (LONG) HIUSHORT(mp1);
  339.  
  340.         if (global.usPtGrabbed != -1)
  341.         {
  342.         hps = WinGetPS(hwnd);
  343.         Paint(hps, FALSE);
  344.  
  345.         *(global.pptl+global.usPtGrabbed) = ptl;
  346.  
  347.         Paint(hps, FALSE);
  348.         WinReleasePS(hps);
  349.         }
  350.     }
  351. }
  352.  
  353.  
  354.  
  355.  
  356. /************************************************************************
  357. *
  358. *   ButtonUp
  359. *
  360. ************************************************************************/
  361.  
  362. VOID
  363. ButtonUp(hwnd, usMsg)
  364. HWND hwnd;
  365. USHORT usMsg;
  366. {
  367.     int i;
  368.     HPS hps;
  369.  
  370.  
  371.     if (hwnd == global.hwnd)
  372.     if (global.fDragging)
  373.     {
  374.         global.fDragging = FALSE;
  375.         if (global.usPtGrabbed != -1)
  376.         {
  377.         if (usMsg == WM_BUTTON2UP)
  378.         {
  379.             hps = WinGetPS(hwnd);
  380.             Paint(hps, FALSE);
  381.  
  382.             if ((i = global.usPtGrabbed) < (int) global.cptl-1)
  383.             while (i < (int) global.cptl-1)
  384.             {
  385.                 global.pptl[i] = global.pptl[i+1];
  386.                 ++i;
  387.             }
  388.  
  389.             --global.cptl;
  390.             global.usPtGrabbed = -1;
  391.  
  392.             Paint(hps, FALSE);
  393.             WinReleasePS(hps);
  394.         }
  395.         else    /* WM_BUTTON1UP */
  396.             global.usPtGrabbed = -1;
  397.         }
  398.     }
  399. }
  400.  
  401.  
  402.  
  403.  
  404. /************************************************************************
  405. *
  406. *   ButtonDown
  407. *
  408. ************************************************************************/
  409.  
  410. VOID
  411. ButtonDown(hwnd, usMsg, mp1)
  412. HWND hwnd;
  413. USHORT usMsg;
  414. MPARAM mp1;
  415. {
  416.     POINTL ptl;
  417.     HPS hps;
  418.     USHORT usNewPtGrabbed;
  419.  
  420.  
  421.     if (hwnd == global.hwnd)
  422.     if (!global.fDragging)
  423.     {
  424.         global.fDragging = TRUE;
  425.  
  426.         ptl.x = (LONG) LOUSHORT(mp1);
  427.         ptl.y = (LONG) HIUSHORT(mp1);
  428.  
  429.         if ((usNewPtGrabbed = IsPtInList(&ptl)) != -1)
  430.         global.usPtGrabbed = usNewPtGrabbed;
  431.  
  432.         if (usMsg == WM_BUTTON1DOWN)
  433.         {
  434.         hps = WinGetPS(hwnd);
  435.         Paint(hps, FALSE);
  436.  
  437.         if (usNewPtGrabbed == -1)
  438.             global.usPtGrabbed = AddPtToList(&ptl);
  439.         else
  440.             global.usPtGrabbed = usNewPtGrabbed;
  441.  
  442.         Paint(hps, FALSE);
  443.         WinReleasePS(hps);
  444.  
  445.         if (global.usPtGrabbed == -1)
  446.             MyMessageBox(global.hwnd, "Cannot add any more points.");
  447.         }
  448.     }
  449. }
  450.  
  451.  
  452.  
  453.  
  454. /************************************************************************
  455. *
  456. *   IsPtInList
  457. *
  458. ************************************************************************/
  459.  
  460. USHORT
  461. IsPtInList(pptl)
  462. PPOINTL pptl;
  463. {
  464.     int i;
  465.  
  466.  
  467.     /* try to find pptl in the points we already have */
  468.     for (i = 0; i < (int) global.cptl; ++i)
  469.     if (((abs(pptl->x - global.pptl[i].x))
  470.         <= (LONG) global.ulHitPrecision)
  471.      && ((abs(pptl->y - global.pptl[i].y))
  472.         <= (LONG) global.ulHitPrecision))
  473.         return i;
  474.  
  475.     /* couldn't find it */
  476.     return -1;
  477. }
  478.  
  479.  
  480.  
  481.  
  482. /************************************************************************
  483. *
  484. *   AddPtToList
  485. *
  486. ************************************************************************/
  487.  
  488. USHORT
  489. AddPtToList(pptl)
  490. PPOINTL pptl;
  491. {
  492.     int i, j;
  493.  
  494.     if (global.cptl < CPTLMAX)
  495.     {
  496.     /* check for new points lying on a line segment */
  497.     for (i = 0; i < (int) (global.cptl - 1L); ++i)
  498.         if (IsPtCloseToLine(&global.pptl[i], &global.pptl[i+1], pptl))
  499.         {
  500.         for (j = (int) global.cptl; j > i+1; --j)
  501.             global.pptl[j] = global.pptl[j - 1];
  502.         global.pptl[i+1] = *pptl;
  503.         ++global.cptl;
  504.         return i+1;
  505.         }
  506.  
  507.     /* append the point */
  508.  
  509.     i = (int) global.cptl;
  510.     global.pptl[i] = *pptl;
  511.     ++global.cptl;
  512.     return i;
  513.     }
  514.  
  515.     return -1;
  516. }
  517.  
  518.  
  519.  
  520.  
  521. /************************************************************************
  522. *
  523. *   IsPtCloseToLine
  524. *
  525. ************************************************************************/
  526.  
  527. BOOL
  528. IsPtCloseToLine(pptl1, pptl2, pptlTest)
  529. PPOINTL pptl1;
  530. PPOINTL pptl2;
  531. PPOINTL pptlTest;
  532. {
  533.     POINTL ptlLL, ptlUR;
  534.     LONG dx, dy, yIntercept, result;
  535.  
  536.  
  537.     /* find the bounding box of the line segment */
  538.  
  539.     ptlLL = *pptl1;    /* assume line goes lower left to upper right */
  540.     ptlUR = *pptl2;
  541.     if (pptl1->x > pptl2->x)
  542.     SwapLong(&ptlLL.x, &ptlUR.x);
  543.     if (pptl1->y > pptl2->y)
  544.     SwapLong(&ptlLL.y, &ptlUR.y);
  545.  
  546.  
  547.     /* adjust the bounding box if it's too narrow */
  548.  
  549.     dx = pptl2->x - pptl1->x;
  550.     if (abs(dx) <= (LONG) (global.ulHitPrecision >> 1))
  551.     {
  552.     ptlLL.x -= (LONG) (global.ulHitPrecision >> 1);
  553.     ptlUR.x += (LONG) (global.ulHitPrecision >> 1);
  554.     }
  555.     dy = pptl2->y - pptl1->y;
  556.     if (abs(dy) <= (LONG) (global.ulHitPrecision >> 1))
  557.     {
  558.     ptlLL.y -= (LONG) (global.ulHitPrecision >> 1);
  559.     ptlUR.y += (LONG) (global.ulHitPrecision >> 1);
  560.     }
  561.  
  562.  
  563.     /* see if the test point is in the bounding box of the line segment */
  564.  
  565.     if ((pptlTest->x >= ptlLL.x) &&
  566.     (pptlTest->x <= ptlUR.x) &&
  567.     (pptlTest->y >= ptlLL.y) &&
  568.     (pptlTest->y <= ptlUR.y))
  569.     {
  570.     /* test for special cases */
  571.  
  572.     if (dx == 0)
  573.     {
  574.         if (abs(pptlTest->x - pptl1->x) <= (LONG) global.ulHitPrecision)
  575.         return TRUE;
  576.         else
  577.         return FALSE;
  578.     }
  579.  
  580.     if (dy == 0)
  581.     {
  582.         if (abs(pptlTest->y - pptl1->y) <= (LONG) global.ulHitPrecision)
  583.         return TRUE;
  584.         else
  585.         return FALSE;
  586.     }
  587.  
  588.  
  589.     /* test for general case */
  590.  
  591.     yIntercept = pptl1->y - (pptl1->x * dy) / dx;
  592.  
  593.     result = pptlTest->y - (pptlTest->x * dy / dx) - yIntercept;
  594.     if (abs(result) <= (LONG) global.ulHitPrecision)
  595.         return TRUE;
  596.     }
  597.  
  598.     return FALSE;
  599. }
  600.  
  601.  
  602.  
  603.  
  604. /************************************************************************
  605. *
  606. *   SwapLong
  607. *
  608. ************************************************************************/
  609.  
  610. VOID
  611. SwapLong(pl1, pl2)
  612. PLONG pl1, pl2;
  613. {
  614.     LONG lTmp;
  615.  
  616.     lTmp = *pl1;
  617.     *pl1 = *pl2;
  618.     *pl2 = lTmp;
  619. }
  620.  
  621.  
  622.  
  623.  
  624. /************************************************************************
  625. *
  626. *   Close
  627. *
  628. ************************************************************************/
  629.  
  630. VOID
  631. Close(hwnd)
  632. HWND hwnd;
  633. {
  634.     WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  635. }
  636.  
  637.  
  638.  
  639.  
  640. /************************************************************************
  641. *
  642. *   Command
  643. *
  644. *   Dispatches menu commands to the proper handlers.
  645. *
  646. ************************************************************************/
  647.  
  648. #define UPDATE_MENU_BOOL(var, val)                \
  649.     {                            \
  650.         TOGGLE_BOOL((var));                 \
  651.         TOGGLE_MENU_ITEM(global.hwndFrame, (val), (var));    \
  652.     }
  653.  
  654. #define UPDATE_MENU_LIST(var, val)                \
  655.     {                            \
  656.         UNCHECK_MENU_ITEM(global.hwndFrame, (var));     \
  657.         (var) = (val);                    \
  658.         CHECK_MENU_ITEM(global.hwndFrame, (var));        \
  659.     }
  660.  
  661. VOID
  662. Command(hwnd, id)
  663. HWND hwnd;
  664. USHORT id;
  665. {
  666.     HPS hps;
  667.     BOOL fRedraw = FALSE;
  668.     int rc;
  669.  
  670.     switch (id)
  671.     {
  672.     case IDM_ABOUT:
  673.     rc = WinDlgBox(HWND_DESKTOP, hwnd, AboutDlgProc, (HMODULE) NULL, IDD_ABOUT, NULL);
  674.     fRedraw = FALSE;
  675.     break;
  676.  
  677.     case IDM_NOPRIM:
  678.     global.flPrim = 0L;
  679.     TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYLINE, 0);
  680.     TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYFILLET, 0);
  681.     TOGGLE_MENU_ITEM(global.hwndFrame, IDM_POLYSPLINE, 0);
  682.     fRedraw = TRUE;
  683.     break;
  684.  
  685.     case IDM_POLYLINE:
  686.     global.flPrim ^= PRIM_POLYLINE;
  687.     TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYLINE));
  688.     fRedraw = TRUE;
  689.     break;
  690.  
  691.     case IDM_POLYFILLET:
  692.     global.flPrim ^= PRIM_POLYFILLET;
  693.     TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYFILLET));
  694.     fRedraw = TRUE;
  695.     break;
  696.  
  697.     case IDM_POLYSPLINE:
  698.     global.flPrim ^= PRIM_POLYSPLINE;
  699.     TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POLYSPLINE));
  700.     fRedraw = TRUE;
  701.     break;
  702.  
  703.     case IDM_POINTARC:
  704.     global.flPrim ^= PRIM_POINTARC;
  705.     TOGGLE_MENU_ITEM(global.hwndFrame, id, (global.flPrim & PRIM_POINTARC));
  706.     fRedraw = TRUE;
  707.     break;
  708.  
  709.     case IDM_CTLPOINTS:
  710.     UPDATE_MENU_BOOL(global.fDisplayControlPoints, IDM_CTLPOINTS);
  711.     fRedraw = TRUE;
  712.     break;
  713.  
  714.     case IDM_CLEARALL:
  715.     global.cptl = 0L;
  716.     fRedraw = TRUE;
  717.     break;
  718.  
  719.     case IDM_COPY:
  720.     /*
  721.         To put this image on the clipboard, create a Metafile DC.
  722.  
  723.         Associate a presentation space with the DC, then play the
  724.         drawing orders into the metafile.
  725.     */
  726.     global.dop.pszLogAddress = NULL;
  727.     global.dop.pszDriverName = "DISPLAY";
  728.     global.dop.pdriv = NULL;
  729.     global.dop.pszDataType = NULL;
  730.  
  731.     global.hdcMetafile = DevOpenDC(global.hab, OD_METAFILE,
  732.                 "*", 4L, (PDEVOPENDATA) &global.dop, NULL);
  733.     global.hpsMetafile = GpiCreatePS(global.hab, global.hdcMetafile,
  734.                     &global.sizlPage, PU_PELS | GPIA_ASSOC);
  735.  
  736.     Paint(global.hpsMetafile, TRUE);
  737.     /*
  738.         Clean up.  A handle to the metafile is obtained when
  739.         calling DevCloseDC().
  740.     */
  741.     GpiAssociate(global.hpsMetafile, NULL);
  742.     GpiDestroyPS(global.hpsMetafile);
  743.     global.hItem = (ULONG) DevCloseDC(global.hdcMetafile);
  744.     /*
  745.         Be sure to empty the clipboard of other data.  This will
  746.         also empty previous data stored in other formats.
  747.         Then, set the clipboard data with type METAFILE, passing
  748.         the handle to our metafile.
  749.     */
  750.     if (WinOpenClipbrd(global.hab)) {
  751.         WinEmptyClipbrd(global.hab);
  752.         WinSetClipbrdData(global.hab,global.hItem, CF_METAFILE, CFI_HANDLE);
  753.         WinCloseClipbrd(global.hab);
  754.     }
  755.     break;
  756.     }
  757.  
  758.     if (fRedraw)
  759.     {
  760.     hps = WinGetPS(hwnd);
  761.     Paint(hps, TRUE);
  762.     WinReleasePS(hps);
  763.     }
  764. }
  765.  
  766.  
  767.  
  768.  
  769. /************************************************************************
  770. *
  771. *   Paint
  772. *
  773. ************************************************************************/
  774.  
  775. VOID
  776. Paint(hps, fClearScreen)
  777. HPS  hps;
  778. BOOL fClearScreen;
  779. {
  780.     LINEBUNDLE lb;
  781.     RECTL rcl;
  782.     if (fClearScreen)
  783.     {
  784.     /* clear the screen */
  785.     WinQueryWindowRect(global.hwnd, &rcl);
  786.     GpiBitBlt(hps, NULL, 2L, (PPOINTL) &rcl, ROP_ONE, 0L);
  787.     }
  788.  
  789.  
  790.     if (global.cptl > 0L)
  791.     {
  792.     if (global.fDisplayControlPoints)
  793.     {
  794.         if (fClearScreen)
  795.         /* draw all the control points */
  796.         DrawControlPoints(hps, global.cptl, global.pptl);
  797.         else if (global.usPtGrabbed != -1)
  798.         /* draw just the control point that moved */
  799.         DrawControlPoints(hps, 1L, global.pptl+global.usPtGrabbed);
  800.     }
  801.  
  802.     /* set mix mode to xor */
  803.     lb.usMixMode = FM_XOR;
  804.     GpiSetAttrs(hps, PRIM_LINE, LBB_MIX_MODE, 0L, &lb);
  805.  
  806.     /* draw the current primitives */
  807.  
  808.     if (global.flPrim & PRIM_POLYLINE)
  809.     {
  810.         lb.lColor = CLR_BROWN;
  811.         GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  812.         DrawPrimitive(hps, IDM_POLYLINE);
  813.     }
  814.  
  815.     if (global.flPrim & PRIM_POLYFILLET)
  816.     {
  817.         lb.lColor = CLR_DARKCYAN;
  818.         GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  819.         DrawPrimitive(hps, IDM_POLYFILLET);
  820.     }
  821.  
  822.     if (global.flPrim & PRIM_POLYSPLINE)
  823.     {
  824.         lb.lColor = CLR_DARKPINK;
  825.         GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  826.         DrawPrimitive(hps, IDM_POLYSPLINE);
  827.     }
  828.  
  829.     if (global.flPrim & PRIM_POINTARC)
  830.     {
  831.         lb.lColor = CLR_BACKGROUND;
  832.         GpiSetAttrs(hps, PRIM_LINE, LBB_COLOR, 0L, &lb);
  833.         DrawPrimitive(hps, IDM_POINTARC);
  834.     }
  835.     }
  836. }
  837.  
  838.  
  839.  
  840.  
  841. /************************************************************************
  842. *
  843. *   DrawPrimitive
  844. *
  845. ************************************************************************/
  846.  
  847. VOID
  848. DrawPrimitive(hps, usPrim)
  849. HPS hps;
  850. USHORT usPrim;
  851. {
  852.     switch ( usPrim )
  853.     {
  854.     case IDM_POLYLINE:
  855.     DrawPolyLine(hps);
  856.     break;
  857.  
  858.     case IDM_POLYFILLET:
  859.     DrawPolyFillet(hps);
  860.     break;
  861.  
  862.     case IDM_POLYSPLINE:
  863.     DrawPolySpline(hps);
  864.     break;
  865.  
  866.     case IDM_POINTARC:
  867.     DrawPointArc(hps);
  868.     break;
  869.     }
  870. }
  871.  
  872.  
  873.  
  874.  
  875. /************************************************************************
  876. *
  877. *   DrawPolyLine
  878. *
  879. ************************************************************************/
  880.  
  881. VOID
  882. DrawPolyLine(hps)
  883. HPS hps;
  884. {
  885.     GpiSetCurrentPosition( hps, global.pptl );
  886.     GpiPolyLine( hps, global.cptl-1L, global.pptl+1 );
  887. }
  888.  
  889.  
  890.  
  891.  
  892. /************************************************************************
  893. *
  894. *   DrawPolyFillet
  895. *
  896. ************************************************************************/
  897.  
  898. VOID
  899. DrawPolyFillet(hps)
  900. HPS hps;
  901. {
  902.     if (global.cptl > 2)
  903.     {
  904.     GpiSetCurrentPosition( hps, global.pptl );
  905.     GpiPolyFillet( hps, global.cptl-1L, global.pptl+1 );
  906.     }
  907. }
  908.  
  909.  
  910.  
  911.  
  912. /************************************************************************
  913. *
  914. *   DrawPolySpline
  915. *
  916. ************************************************************************/
  917.  
  918. VOID
  919. DrawPolySpline(hps)
  920. HPS hps;
  921. {
  922.     USHORT cptSlack;    /* # points in pptl not usable by PolySpline */
  923.  
  924.     /* GpiPolySpline expects the number of points to be a
  925.        multiple of 3.  If we have a non-multiple of three,
  926.        (excluding the first point, which we've used to set
  927.        the current position), only pass the largest multiple
  928.        of three, saving the rest for the next go-round. */
  929.  
  930.     cptSlack = (int)((global.cptl-1L) % 3) + 1;
  931.     GpiSetCurrentPosition( hps, global.pptl );
  932.     GpiPolySpline( hps, global.cptl-cptSlack,
  933.            global.pptl+1 );
  934. }
  935.  
  936.  
  937.  
  938.  
  939. /************************************************************************
  940. *
  941. *   DrawPointArc
  942. *
  943. ************************************************************************/
  944.  
  945. VOID
  946. DrawPointArc(hps)
  947. HPS hps;
  948. {
  949.     if (global.cptl >= 3L)
  950.     {
  951.     GpiSetCurrentPosition( hps, global.pptl );
  952.     GpiPointArc( hps, global.pptl+1 );
  953.     }
  954. }
  955.  
  956.  
  957.  
  958.  
  959. /************************************************************************
  960. *
  961. *   DrawControlPoints
  962. *
  963. ************************************************************************/
  964.  
  965. VOID
  966. DrawControlPoints(hps, cptl, pptl)
  967. HPS hps;
  968. LONG cptl;
  969. PPOINTL pptl;
  970. {
  971.     MARKERBUNDLE mb;
  972.  
  973.     mb.lColor = CLR_TRUE;
  974.     mb.usMixMode = FM_XOR;
  975.     GpiSetAttrs(hps, PRIM_MARKER, MBB_COLOR | MBB_MIX_MODE, 0L, &mb);
  976.  
  977.     GpiPolyMarker(hps, cptl, pptl);
  978. }
  979.  
  980.  
  981.  
  982.  
  983. /************************************************************************
  984. *
  985. *   MyMessageBox
  986. *
  987. *   Displays a message box with the given string.  To simplify matters,
  988. *   the box will always have the same title ("PolyLine Editor"), will always
  989. *   have a single button ("Ok"), will always have an exclamation point
  990. *   icon, and will always be application modal.
  991. *
  992. ************************************************************************/
  993.  
  994. VOID
  995. MyMessageBox(hWnd, sz)
  996. HWND hWnd;
  997. PSZ sz;
  998. {
  999.     static char *szTitle = "PolyLine Editor";
  1000.  
  1001.     WinMessageBox(HWND_DESKTOP, hWnd, sz, szTitle, 0,
  1002.           MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL);
  1003. }
  1004.  
  1005. MRESULT CALLBACK AboutDlgProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2) {
  1006. /*
  1007.     About... dialog procedure
  1008. */
  1009.     switch(msg) {
  1010.     case WM_COMMAND:
  1011.         switch(COMMANDMSG(&msg)->cmd) {
  1012.         case DID_OK: WinDismissDlg(hDlg, TRUE); break;
  1013.         default: break;
  1014.         }
  1015.     default: return WinDefDlgProc(hDlg, msg, mp1, mp2);
  1016.     }
  1017.     return FALSE;
  1018. }
  1019.