home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / WHEEL1.ZIP / WHEEL.C < prev    next >
Text File  |  1990-02-12  |  25KB  |  795 lines

  1. // Includes
  2. // --------
  3.    #define INCL_WIN
  4.    #define INCL_GPI
  5.    #define INCL_DOS
  6.  
  7.    #include <os2.h>
  8.  
  9.    #include "stdlib.h"                 // Changed from <..> for Eikon
  10.    #include "math.h"                   // Changed from <..> for Eikon
  11.  
  12.    #include "Wheel.H"
  13.  
  14.    #include "AllocMem.H"
  15.  
  16.  
  17. // Constants
  18. // ---------
  19.    #define COLOR_WHEEL_RADIUS 1024L    // ColorWheel radius in world units
  20.    #define COLOR_WHEEL_RINGS     8     // Number of rings in ColorWheel
  21.    #define COLOR_WHEEL_PIES     12     // Number of pies in ColorWheel
  22.  
  23.    const USHORT cbExtraData            // Extra window storage
  24.               = (2 * sizeof (PVOID));
  25.  
  26.  
  27. // Precomputed Data
  28. // ----------------
  29.    typedef struct _PRECOMP
  30.      {FIXED fxTheta;                   // Pie start angle
  31.       double sinTheta, cosTheta;       // Sine, cosine of above
  32.      } PRECOMP;
  33.  
  34.  
  35. // Intra-instance Data
  36. // -------------------
  37.    typedef struct _INST
  38.      {HPS hps;                         // Presentation space handle
  39.       BOOL fPolyChrome;                // TRUE==in polychrome mode
  40.       BOOL fHourGlass;                 // TRUE==show hour glass pointer
  41.       BOOL fCapture;                   // TRUE==mouse is captured
  42.       SHORT cEatMove;                  // Count of WM_MOUSEMOVE messages to ignore
  43.       PRECOMP prec[COLOR_WHEEL_PIES+1];// Precomputed values
  44.       FIXED fxSweep;                   // Precomputed sweep angle (degrees)
  45.       LONG lSweep;                     // Precomputed sweep angle (radians)
  46.       LONG lWidth;                     // Precomputed ring width
  47.       COLOR rgb;                       // Current color in RGB form
  48.       double h, s, v;                  // Current color in HSV form
  49.      } INST;
  50.  
  51.    typedef INST *PINST;
  52.  
  53.  
  54. // Function Declarations
  55. // ---------------------
  56.    MRESULT FAR      ColorWheelClick         (PINST, HWND, SHORT, SHORT, BOOL);
  57.    MRESULT FAR      ColorWheelCreate        (HWND);
  58.    MRESULT FAR      ColorWheelDestroy       (PINST, HWND);
  59.    MRESULT FAR      ColorWheelDoubleClick   (PINST, HWND);
  60.    VOID    FAR      ColorWheelDraw          (PINST, HWND);
  61.    VOID    EXPENTRY ColorWheelInitialize    (HAB);
  62.    MRESULT FAR      ColorWheelMouseMove     (PINST, HWND, SHORT, SHORT);
  63.    MRESULT FAR      ColorWheelPaint         (PINST, HWND);
  64.    MRESULT FAR      ColorWheelRelease       (PINST, HWND);
  65.    MRESULT FAR      ColorWheelSamplePaint   (HWND);
  66.    MRESULT EXPENTRY ColorWheelSampleWndProc (HWND, USHORT, MPARAM, MPARAM);
  67.    MRESULT FAR      ColorWheelSize          (PINST, HWND);
  68.    MRESULT EXPENTRY ColorWheelWndProc       (HWND, USHORT, MPARAM, MPARAM);
  69.  
  70.    COLOR   FAR      HSVtoRGB                (double, double, double);
  71.    VOID    FAR      RGBtoHSV                (COLOR, double *, double *, double *);
  72.  
  73.  
  74. // Function: ColorWheelClick - Click on ColorWheel
  75. // -----------------------------------------------
  76.    MRESULT FAR ColorWheelClick (pinst, hwnd, x, y, fRound)
  77.  
  78.       PINST pinst;                     // -->instance data
  79.       HWND hwnd;                       // Window handle
  80.       SHORT x;                         // X coordinate of click
  81.       SHORT y;                         // Y coordinate of click
  82.       BOOL fRound;                     // TRUE==round color
  83.  
  84.    // Local data items:
  85.  
  86.      {POINTL ptl;                      // Cartesian co-ordinates of selected point
  87.       double r, t;                     // Polar co-ordinates of selected point
  88.  
  89.       static double dR2D = 360.0 / (2.0 * 3.14159265359);
  90.  
  91.    // Capture the mouse
  92.  
  93.       pinst->fCapture = TRUE;
  94.       WinSetCapture (HWND_DESKTOP, hwnd);
  95.  
  96.    // Determine selected point in presentation page units
  97.  
  98.       ptl.x = (LONG) x;
  99.       ptl.y = (LONG) y;
  100.       GpiConvert (pinst->hps, CVTC_DEVICE, CVTC_WORLD, 1L, &ptl);
  101.  
  102.    // Convert cartesian co-ordinates of selected point to polar co-ordinates
  103.  
  104.       r = sqrt ((double) ((ptl.x * ptl.x) + (ptl.y * ptl.y)));
  105.       t = dR2D * atan2 ((double) ptl.y, (double) ptl.x);
  106.       if (t < 0.0) t = 360.0 + t;
  107.  
  108.    // Exit immediately if click was outside of Color Wheel
  109.  
  110.       if (r > (double) COLOR_WHEEL_RADIUS)
  111.          return (MRESULT) NULL;
  112.  
  113.    // If rounding is specified, round polar co-ordinates to nearest segment
  114.  
  115.       if (fRound)
  116.         {r = (double) (((LONG) r / pinst->lWidth) * pinst->lWidth);
  117.          t = (double) (((LONG) t / pinst->lSweep) * pinst->lSweep);
  118.         }
  119.  
  120.    // Get selected HSV values in [0, 1] from polar co-ordinates and
  121.    // convert to RGB values in [0, 256)
  122.  
  123.       if (pinst->fPolyChrome)
  124.         {pinst->h = t / 360.0;
  125.          pinst->s = r / (double) (COLOR_WHEEL_RADIUS - ((fRound)? pinst->lWidth : 0L));
  126.          pinst->v = 1.0;
  127.         }
  128.       else
  129.         {pinst->s = 1.0 - (t / (360.0 - (double) ((fRound)? pinst->lSweep : 0L)));
  130.          pinst->v = r / (double) (COLOR_WHEEL_RADIUS - ((fRound)? pinst->lWidth : 0L));
  131.         }
  132.       pinst->rgb = HSVtoRGB (pinst->h, pinst->s, pinst->v);
  133.  
  134.    // Tell owner of new color.
  135.  
  136.       WinSendMsg (WinQueryWindow (hwnd, QW_OWNER, FALSE), WM_CONTROL,
  137.         MPFROM2SHORT (WinQueryWindowUShort (hwnd, QWS_ID), COLOR_WHEEL_NOTIFY_NEWCOLOR),
  138.         (MPARAM) pinst->rgb);
  139.  
  140.    // Indicate mouse click processing is complete
  141.  
  142.       return (MRESULT) NULL;
  143.  
  144.      }
  145.  
  146.  
  147. // Function: ColorWheelCreate - Create ColorWheel
  148. // ----------------------------------------------
  149.    MRESULT FAR ColorWheelCreate (hwnd)
  150.  
  151.       HWND hwnd;                       // Window handle
  152.  
  153.    // Define function data
  154.  
  155.      {PINST pinst;                     // -->instance data
  156.       SIZEL sizl;                      // Presentation space size
  157.       HDC hdc;                         // Device context
  158.       SHORT iPie;                      // Pie number
  159.       SHORT cPies;                     // Pie count
  160.       POINTL ptl;                      // Temporary point
  161.  
  162.       static double dD2R = (2.0 * 3.14159265359) / 360.0;
  163.  
  164.    // Allocate the Color Wheel instance data
  165.  
  166.       pinst = (PINST) AllocMemAlloc ((LONG) sizeof (*pinst));
  167.       WinSetWindowULong (hwnd, QWL_USER + sizeof (PVOID), (ULONG) pinst);
  168.  
  169.    // Acquire a presentation space and initialize basic attributes
  170.  
  171.       hdc = WinOpenWindowDC (hwnd);
  172.       sizl.cx = sizl.cy = 2L * COLOR_WHEEL_RADIUS;
  173.       pinst->hps = GpiCreatePS (NULL, hdc, &sizl, PU_ARBITRARY | GPIF_LONG | GPIT_NORMAL | GPIA_ASSOC);
  174.  
  175.    // Initialize number of pies
  176.  
  177.       cPies =  COLOR_WHEEL_PIES;
  178.  
  179.    // Precompute the sweep angle and segment width
  180.  
  181.       pinst->fxSweep = MAKEFIXED (360 / cPies, 0);
  182.       pinst->lSweep = 360L / (LONG) cPies;
  183.       pinst->lWidth = COLOR_WHEEL_RADIUS / COLOR_WHEEL_RINGS;
  184.  
  185.    // Precompute angles for each pie
  186.  
  187.       for (iPie = 0; iPie < cPies; iPie++)
  188.         {pinst->prec[iPie].fxTheta = (FIXED) ((LONG) pinst->fxSweep * (LONG) iPie);
  189.          pinst->prec[iPie].sinTheta = sin (dD2R * (double) ((LONG) pinst->prec[iPie].fxTheta / 65536L));
  190.          pinst->prec[iPie].cosTheta = cos (dD2R * (double) ((LONG) pinst->prec[iPie].fxTheta / 65536L));
  191.         }
  192.  
  193.    // Add extra entry to make "next pie" computations easier
  194.  
  195.       pinst->prec[cPies].fxTheta = pinst->prec[0].fxTheta;
  196.       pinst->prec[cPies].sinTheta = pinst->prec[0].sinTheta;
  197.       pinst->prec[cPies].cosTheta = pinst->prec[0].cosTheta;
  198.  
  199.    // Draw initial Color Wheel in polychrome
  200.  
  201.       pinst->fPolyChrome = TRUE;
  202.       ColorWheelDraw (pinst, hwnd);
  203.  
  204.    // Initialize selection by simulating a "click" on the origin
  205.  
  206.       ptl.x = ptl.y = 0L;
  207.       GpiConvert (pinst->hps, CVTC_WORLD, CVTC_DEVICE, 1L, &ptl);
  208.       ColorWheelClick (pinst, hwnd, (SHORT) ptl.x, (SHORT) ptl.y, TRUE);
  209.       ColorWheelRelease (pinst, hwnd);
  210.  
  211.    // Indicate initialization complete
  212.  
  213.       return (MRESULT) NULL;
  214.  
  215.      }
  216.  
  217.  
  218. // Function: ColorWheelDestroy - Destroy ColorWheel
  219. // ------------------------------------------------
  220.    MRESULT FAR ColorWheelDestroy (pinst, hwnd)
  221.  
  222.       PINST pinst;                     // -->instance data
  223.       HWND hwnd;                       // Window handle
  224.  
  225.    // HWND is available for future use
  226.  
  227.      {hwnd = hwnd;
  228.  
  229.    // Destroy our presentation space
  230.  
  231.       GpiDestroyPS (pinst->hps);
  232.  
  233.    // Free the Color Wheel instance data
  234.  
  235.       AllocMemFree (pinst);
  236.  
  237.    // Indicate termination complete
  238.  
  239.       return (MRESULT) NULL;
  240.  
  241.      }
  242.  
  243.  
  244. // Function: ColorWheelDoubleClick - Double Click on ColorWheel
  245. // ------------------------------------------------------------
  246.    MRESULT FAR ColorWheelDoubleClick (pinst, hwnd)
  247.  
  248.       PINST pinst;                     // -->instance data
  249.       HWND hwnd;                       // Window handle
  250.  
  251.    // Reverse poly/monochrome Color Wheel status
  252.  
  253.      {pinst->fPolyChrome = !(pinst->fPolyChrome);
  254.  
  255.    // Rebuild and redraw Color Wheel
  256.  
  257.       ColorWheelDraw (pinst, hwnd);
  258.       WinInvalidateRect (hwnd, NULL, FALSE);
  259.  
  260.    // Indicate mouse double click processing is complete
  261.  
  262.       return (MRESULT) NULL;
  263.  
  264.      }
  265.  
  266.  
  267. // Function: ColorWheelDraw - Draw ColorWheel
  268. // ------------------------------------------------
  269.    VOID FAR ColorWheelDraw (pinst, hwnd)
  270.  
  271.       PINST pinst;                     // -->instance data
  272.       HWND hwnd;                       // Window handle
  273.  
  274.    // Local function storage
  275.  
  276.      {ARCPARAMS arcp;                  // Arc parameters
  277.       POINTL ptlStart, ptlEnd;         // Start, end point of arc
  278.       POINTL ptlCenter;                // Center point of arc
  279.       ULONG idSegment;                 // Segment identifier
  280.       SHORT iPie, iRing;               // Pie, ring number
  281.       SHORT cPies, cRings;             // Pie, ring count
  282.       double h, s, v;                  // HSV values in [0, 1]
  283.       COLOR rgb;                       // RGB values in [0, 256)
  284.  
  285.    // Indicate that the hour glass pointer should be displayed
  286.    // and display it.
  287.  
  288.       pinst->fHourGlass = TRUE;
  289.       WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (HWND_DESKTOP, SPTR_WAIT, FALSE));
  290.  
  291.    // Initialize number of pies, rings and segment identifier
  292.  
  293.       cPies =  COLOR_WHEEL_PIES;
  294.       cRings = COLOR_WHEEL_RINGS;
  295.       idSegment = 0L;
  296.  
  297.    // Reset the presentation space to delete any existing segments
  298.  
  299.       GpiResetPS (pinst->hps, GRES_ALL);
  300.  
  301.    // Set initial attributes
  302.  
  303.       GpiSetDrawingMode (pinst->hps, DM_RETAIN);
  304.       GpiCreateLogColorTable (pinst->hps, LCOL_RESET, LCOLF_RGB, NULL, NULL, NULL);
  305.  
  306.    // Initialize arc parameters
  307.  
  308.       arcp.lP = arcp.lQ = COLOR_WHEEL_RADIUS / cRings;
  309.       arcp.lR = arcp.lS = 0L;
  310.       GpiSetArcParams (pinst->hps, &arcp);
  311.  
  312.    // Initialize center point
  313.  
  314.       ptlCenter.x = ptlCenter.y = 0L;
  315.  
  316.    // Draw pies clockwise
  317.  
  318.       for (iPie = 0; iPie < cPies; iPie++)
  319.  
  320.       // Calculate start, end of innermost ring for this arc
  321.  
  322.         {ptlStart.x = (LONG) (pinst->prec[iPie].cosTheta * arcp.lP);
  323.          ptlStart.y = (LONG) (pinst->prec[iPie].sinTheta * arcp.lQ);
  324.          ptlEnd.x = (LONG) (pinst->prec[iPie+1].cosTheta * arcp.lP);
  325.          ptlEnd.y = (LONG) (pinst->prec[iPie+1].sinTheta * arcp.lQ);
  326.  
  327.       // Draw rings from the outside in
  328.  
  329.          for (iRing = cRings-1; iRing >= 0; iRing--)
  330.  
  331.          // Build HSV values in [0, 1] from pie, ring number and
  332.          // convert to RGB values in [0, 256)
  333.  
  334.            {if (pinst->fPolyChrome)
  335.               {h = (double) iPie / (double) cPies;
  336.                s = (double) iRing / (double) (cRings-1);
  337.                v = 1.0;
  338.               }
  339.             else
  340.               {h = pinst->h;
  341.                s = 1.0 - ((double) iPie / (double) (cPies-1));
  342.                v = (double) iRing / (double) (cRings-1);
  343.               }
  344.             rgb = HSVtoRGB (h, s, v);
  345.  
  346.          // Initialize arc segment
  347.  
  348.             GpiOpenSegment (pinst->hps, ++idSegment);
  349.             GpiSetTag (pinst->hps, (idSegment << 24) + rgb);
  350.  
  351.          // Draw arc segment in color
  352.  
  353.             GpiSetColor (pinst->hps, rgb);
  354.             GpiBeginArea (pinst->hps, BA_NOBOUNDARY);
  355.             GpiMove (pinst->hps, &ptlCenter);
  356.             GpiPartialArc (pinst->hps, &ptlCenter, MAKEFIXED ((SHORT) iRing+1, 0),
  357.               pinst->prec[iPie].fxTheta, pinst->fxSweep);
  358.             GpiEndArea (pinst->hps);
  359.  
  360.          // Outline the arc segment
  361.  
  362.             GpiSetColor (pinst->hps, 0x00000000L);
  363.             GpiMove (pinst->hps, &ptlStart);
  364.             GpiPartialArc (pinst->hps, &ptlCenter, MAKEFIXED ((SHORT) iRing+1, 0),
  365.               pinst->prec[iPie].fxTheta, pinst->fxSweep);
  366.             GpiLine (pinst->hps, &ptlEnd);
  367.  
  368.          // Terminate arc segment
  369.  
  370.             GpiCloseSegment (pinst->hps);
  371.  
  372.          // Loop until all rings in this pie are drawn
  373.  
  374.            }
  375.  
  376.       // Loop until all pies in the wheel are drawn
  377.  
  378.         }
  379.  
  380.    // Indicate that the regular pointer should be displayed
  381.    // and display it.
  382.  
  383.       pinst->fHourGlass = FALSE;
  384.       WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, FALSE));
  385.  
  386.    // Force a resize of the window
  387.  
  388.       ColorWheelSize (pinst, hwnd);
  389.  
  390.      }
  391.  
  392.  
  393. // Function: ColorWheelInitialize - Initialize ColorWheel processing
  394. // -----------------------------------------------------------------
  395.    VOID EXPENTRY ColorWheelInitialize (hab)
  396.  
  397.       HAB hab;                         // Application anchor block
  398.  
  399.    // Define function data
  400.  
  401.      {static DOSFSRSEM dosfsrs;        // Semaphore to block registration
  402.       static BOOL fRegistered = FALSE; // TRUE if already registered
  403.  
  404.    // Block the actions that follow such that only one process at a
  405.    // time executes them.
  406.  
  407.       DosFSRamSemRequest (&dosfsrs, SEM_INDEFINITE_WAIT);
  408.  
  409.    // Once only, perform initialization.
  410.  
  411.       if (! fRegistered)
  412.  
  413.       // Register ColorWheel window class
  414.  
  415.         {WinRegisterClass (hab, COLOR_WHEEL_CLASS, ColorWheelWndProc, /*CS_PUBLIC |*/ CS_CLIPCHILDREN | CS_SIZEREDRAW, cbExtraData);
  416.  
  417.       // Register ColorWheelSample window class
  418.  
  419.          WinRegisterClass (hab, COLOR_WHEEL_SAMPLE_CLASS, ColorWheelSampleWndProc, /*CS_PUBLIC |*/ CS_CLIPCHILDREN | CS_SIZEREDRAW | CS_SYNCPAINT, cbExtraData);
  420.  
  421.       // Indicate initialization complete
  422.  
  423.        /*fRegistered = TRUE;*/
  424.         }
  425.  
  426.    // Release the block and return
  427.  
  428.       DosFSRamSemClear (&dosfsrs);
  429.  
  430.      }
  431.  
  432.  
  433. // Function: ColorWheelMouseMove - Mouse Move on ColorWheel
  434. // --------------------------------------------------------
  435.    MRESULT FAR ColorWheelMouseMove (pinst, hwnd, x, y)
  436.  
  437.       PINST pinst;                     // -->instance data
  438.       HWND hwnd;                       // Window handle
  439.       SHORT x;                         // X coordinate of click
  440.       SHORT y;                         // Y coordinate of click
  441.  
  442.    // Display appropriate pointer
  443.  
  444.      {WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (HWND_DESKTOP,
  445.         (pinst->fHourGlass)? SPTR_WAIT : SPTR_ARROW, FALSE));
  446.  
  447.    // If we have captured the mouse, simulate a mouse click
  448.  
  449.       if ((pinst->fCapture) && (pinst->cEatMove-- <= 0))
  450.          ColorWheelClick (pinst, hwnd, x, y, FALSE);
  451.  
  452.    // Indicate mouse move processing is complete
  453.  
  454.       return (MRESULT) NULL;
  455.  
  456.      }
  457.  
  458.  
  459. // Function: ColorWheelPaint - Paint ColorWheel
  460. // --------------------------------------------
  461.    MRESULT FAR ColorWheelPaint (pinst, hwnd)
  462.  
  463.       PINST pinst;                     // -->instance data
  464.       HWND hwnd;                       // Window handle
  465.  
  466.    // Define function data
  467.  
  468.      {HPS hps;                         // Presentation space
  469.  
  470.    // Indicate that the hour glass pointer should be displayed
  471.    // and display it.
  472.  
  473.       pinst->fHourGlass = TRUE;
  474.       WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (HWND_DESKTOP, SPTR_WAIT, FALSE));
  475.  
  476.    // Initialize painting, draw all segments and terminate painting
  477.  
  478.       hps = WinBeginPaint (hwnd, pinst->hps, NULL);
  479.       GpiDrawChain (pinst->hps);
  480.       WinEndPaint (hps);
  481.  
  482.    // Indicate that the regular pointer should be displayed
  483.    // and display it.
  484.  
  485.       pinst->fHourGlass = FALSE;
  486.       WinSetPointer (HWND_DESKTOP, WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, FALSE));
  487.  
  488.    // Indicate painting is complete
  489.  
  490.       return (MRESULT) NULL;
  491.  
  492.      }
  493.  
  494.  
  495. // Function: ColorWheelRelease - Release ColorWheel
  496. // ------------------------------------------------
  497.    MRESULT FAR ColorWheelRelease (pinst, hwnd)
  498.  
  499.       PINST pinst;                     // -->instance data
  500.       HWND hwnd;                       // Window handle
  501.  
  502.    // HWND is available for future use
  503.  
  504.      {hwnd = hwnd;
  505.  
  506.    // Release the mouse
  507.  
  508.       pinst->fCapture = FALSE;
  509.       WinSetCapture (HWND_DESKTOP, NULL);
  510.  
  511.    // Indicate mouse release processing is complete
  512.  
  513.       return (MRESULT) NULL;
  514.  
  515.      }
  516.  
  517.  
  518. // Function: ColorWheelSamplePaint - Paint ColorWheelSample
  519. // --------------------------------------------------------
  520.    MRESULT FAR ColorWheelSamplePaint (hwnd)
  521.  
  522.       HWND hwnd;                       // Window handle
  523.  
  524.    // Define function data
  525.  
  526.      {HPS hps;                         // Presentation space
  527.       RECTL rcl;                       // Window rectangle
  528.  
  529.    // Initialize painting
  530.  
  531.       hps = WinBeginPaint (hwnd, NULL, NULL);
  532.       GpiCreateLogColorTable (hps, LCOL_RESET, LCOLF_RGB, NULL, NULL, NULL);
  533.       WinQueryWindowRect (hwnd, &rcl);
  534.  
  535.    // Draw outline rectangle
  536.  
  537.       rcl.xRight--; rcl.yTop--;
  538.       GpiMove (hps, (PPOINTL) &rcl.xLeft);
  539.       GpiSetColor (hps, 0L);
  540.       GpiBox (hps, DRO_OUTLINE, (PPOINTL) &rcl.xRight, NULL, NULL);
  541.  
  542.    // Fill rectangle with current color
  543.  
  544.       rcl.xLeft++; rcl.yBottom++; rcl.xRight--; rcl.yTop--;
  545.       GpiMove (hps, (PPOINTL) &rcl.xLeft);
  546.       GpiSetColor (hps, WinQueryWindowULong (hwnd, QWL_USER + sizeof (PVOID)));
  547.       GpiBox (hps, DRO_FILL, (PPOINTL) &rcl.xRight, NULL, NULL);
  548.  
  549.    // Terminate painting
  550.  
  551.       WinEndPaint (hps);
  552.  
  553.    // Indicate painting is complete
  554.  
  555.       return (MRESULT) NULL;
  556.  
  557.      }
  558.  
  559.  
  560. // Function: ColorWheelSampleWndProc - ColorWheelSample Window Procedure
  561. // ---------------------------------------------------------------------
  562.    MRESULT EXPENTRY ColorWheelSampleWndProc (hwnd, msg, mp1, mp2)
  563.  
  564.       HWND hwnd;                       // Window handle
  565.       USHORT msg;                      // PM message
  566.       MPARAM mp1;                      // Message parameter
  567.       MPARAM mp2;                      // Message parameter
  568.  
  569.    // Analyze type of message from PM
  570.  
  571.      {switch (msg)
  572.  
  573.        {case WM_CONTROL:
  574.           if (SHORT2FROMMP (mp1) == COLOR_WHEEL_NOTIFY_NEWCOLOR)
  575.             {WinSetWindowULong (hwnd, QWL_USER + sizeof (PVOID), (ULONG) mp2);
  576.              WinInvalidateRect (hwnd, NULL, FALSE);
  577.             }
  578.           return (MRESULT) NULL;
  579.  
  580.         case WM_CREATE:
  581.           WinSetWindowULong (hwnd, QWL_USER + sizeof (PVOID), 0x00FFFFFFL);
  582.           return (MRESULT) NULL;
  583.  
  584.         case WM_PAINT:
  585.           return ColorWheelSamplePaint (hwnd);
  586.  
  587.        }
  588.  
  589.   // Return to PM.
  590.  
  591.      return WinDefWindowProc (hwnd, msg, mp1, mp2);
  592.  
  593.     }
  594.  
  595.  
  596. // Function: ColorWheelSize - Size ColorWheel
  597. // ------------------------------------------
  598.    MRESULT FAR ColorWheelSize (pinst, hwnd)
  599.  
  600.       PINST pinst;                     // -->instance data
  601.       HWND hwnd;                       // Window handle
  602.  
  603.    // Define function data
  604.  
  605.      {SWP swp;                         // Current screen position
  606.       MATRIXLF matlf;                  // Transformation matrix
  607.       POINTL ptl;                      // Temporary point
  608.  
  609.    // Save the new display location.
  610.  
  611.       WinQueryWindowPos (hwnd, &swp);
  612.  
  613.    // Convert screen width units
  614.  
  615.       ptl.x = (LONG) ((swp.cx-1) / 2);
  616.       ptl.y = (LONG) ((swp.cy-1) / 2);
  617.       GpiConvert (pinst->hps, CVTC_DEVICE, CVTC_PAGE, 1L, &ptl);
  618.  
  619.    // Determine the transformation matrix
  620.  
  621.       /* A */ matlf.fxM11 = (FIXED) (65536.0 * ((double) min (ptl.x, ptl.y) / COLOR_WHEEL_RADIUS));
  622.       /* B */ matlf.fxM12 = (FIXED) (0);
  623.       /* C */ matlf.fxM21 = (FIXED) (0);
  624.       /* D */ matlf.fxM22 = (FIXED) (65536.0 * ((double) min (ptl.x, ptl.y) / COLOR_WHEEL_RADIUS));
  625.       /* E */ matlf.lM31 = ptl.x;
  626.       /* F */ matlf.lM32 = ptl.y;
  627.               matlf.lM13 = 0L;
  628.               matlf.lM23 = 0L;
  629.               matlf.lM33 = 1L;
  630.       GpiSetDefaultViewMatrix (pinst->hps, 9L, &(matlf), TRANSFORM_REPLACE);
  631.  
  632.    // Indicate new size acknowledged
  633.  
  634.       return (MRESULT) NULL;
  635.  
  636.      }
  637.  
  638.  
  639. // Function: ColorWheelWndProc - ColorWheel Window Procedure
  640. // ---------------------------------------------------------
  641.    MRESULT EXPENTRY ColorWheelWndProc (hwnd, msg, mp1, mp2)
  642.  
  643.       HWND hwnd;                       // Window handle
  644.       USHORT msg;                      // PM message
  645.       MPARAM mp1;                      // Message parameter
  646.       MPARAM mp2;                      // Message parameter
  647.  
  648.    // Define function data
  649.  
  650.      {PINST pinst;                     // -->instance data
  651.  
  652.    // The location of the Color Wheel instance data
  653.    // is retrieved from the Color Wheel window.
  654.  
  655.       pinst = (PINST) WinQueryWindowULong (hwnd, QWL_USER + sizeof (PVOID));
  656.  
  657.    // Analyze type of message from PM
  658.  
  659.       switch (msg)
  660.  
  661.        {case WM_BUTTON1DOWN:
  662.           pinst->cEatMove = 2;
  663.           ColorWheelClick (pinst, hwnd, SHORT1FROMMP (mp1), SHORT2FROMMP (mp1), TRUE);
  664.           return WinDefWindowProc (hwnd, msg, mp1, mp2);
  665.  
  666.         case WM_BUTTON1DBLCLK:
  667.           return ColorWheelDoubleClick (pinst, hwnd);
  668.  
  669.         case WM_BUTTON1UP:
  670.           return ColorWheelRelease (pinst, hwnd);
  671.  
  672.         case WM_CREATE:
  673.           return ColorWheelCreate (hwnd);
  674.  
  675.         case WM_DESTROY:
  676.           return ColorWheelDestroy (pinst, hwnd);
  677.  
  678.         case WM_PAINT:
  679.           return ColorWheelPaint (pinst, hwnd);
  680.  
  681.         case WM_MOUSEMOVE:
  682.           return ColorWheelMouseMove (pinst, hwnd, SHORT1FROMMP (mp1), SHORT2FROMMP (mp1));
  683.  
  684.         case WM_SIZE:
  685.           return ColorWheelSize (pinst, hwnd);
  686.  
  687.        }
  688.  
  689.   // Return to PM.
  690.  
  691.      return WinDefWindowProc (hwnd, msg, mp1, mp2);
  692.  
  693.     }
  694.  
  695.  
  696. // Function: HSVtoRGB
  697. // ------------------
  698.    COLOR FAR HSVtoRGB (h, s, v)
  699.  
  700.       double h;                        // H value
  701.       double s;                        // S value
  702.       double v;                        // V value
  703.  
  704.    // Define function data
  705.  
  706.      {double r, g, b;                  // Corresponding RGB value
  707.       LONG R, G, B;                    // Integer RGB values
  708.       double p, q, t, f, i;            // Temporary values
  709.  
  710.    // Convert HSV to RGB
  711.  
  712.       if (s == 0.0)
  713.          r = g = b = v;
  714.       else
  715.         {if (h == 1.0) h = 0.0;
  716.          h = h * 6.0;
  717.          i = floor (h);
  718.          f = h - i;
  719.          p = v * (1 - s);
  720.          q = v * (1 - (s * f));
  721.          t = v * (1 - (s * (1 - f)));
  722.          if (i == 0.0)
  723.            {r = v; g = t; b = p;}
  724.          else if (i == 1.0)
  725.            {r = q; g = v; b = p;}
  726.          else if (i == 2.0)
  727.            {r = p; g = v; b = t;}
  728.          else if (i == 3.0)
  729.            {r = p; g = q; b = v;}
  730.          else if (i == 4.0)
  731.            {r = t; g = p; b = v;}
  732.          else if (i == 5.0)
  733.            {r = v; g = p; b = q;}
  734.         }
  735.  
  736.    // Convert RGB values now [0, 1] to [0, 255]
  737.  
  738.       R = (LONG) floor (r * 255.9);
  739.       G = (LONG) floor (g * 255.9);
  740.       B = (LONG) floor (b * 255.9);
  741.  
  742.    // Return color to caller
  743.  
  744.       return (COLOR) ((R << 16) + (G << 8) + B);
  745.  
  746.      }
  747.  
  748.  
  749. // Function: RGBtoHSV
  750. // ------------------
  751.    VOID FAR RGBtoHSV (rgb, ph, ps, pv)
  752.  
  753.       COLOR rgb;                       // RGB value
  754.       double *ph;                      // H value
  755.       double *ps;                      // S value
  756.       double *pv;                      // V value
  757.  
  758.    // Define function data
  759.  
  760.      {double r, g, b;                  // RGB values in [0, 1]
  761.       double rc, gc, bc;               // "Distance" of color from primary
  762.       double minRGB, maxRGB;           // Min, max RGB values
  763.  
  764.    // Extract RGB values in [0, 1]
  765.  
  766.       r = (double) ((rgb & 0x00FF0000L) >> 16) / 255.0;
  767.       g = (double) ((rgb & 0x0000FF00L) >>  8) / 255.0;
  768.       b = (double) (rgb & 0x000000FFL) / 255.0;
  769.  
  770.    // Get min, max RGB values
  771.  
  772.       minRGB = min (r, min (g, b));
  773.       maxRGB = max (r, max (g, b));
  774.  
  775.    // Convert RGB to HSV
  776.  
  777.       *pv = maxRGB;
  778.       if (maxRGB > 0.0)
  779.          *ps = (maxRGB - minRGB) / maxRGB;
  780.       else *ps = *ph = 0.0;
  781.       if (*ps > 0.0)
  782.         {rc = (maxRGB - r) / (maxRGB - minRGB);
  783.          gc = (maxRGB - g) / (maxRGB - minRGB);
  784.          bc = (maxRGB - b) / (maxRGB - minRGB);
  785.          if (r == maxRGB)
  786.             *ph = bc - gc;
  787.          else if (g == maxRGB)
  788.             *ph = 2 + rc - bc;
  789.          else if (b == maxRGB)
  790.             *ph = 4 + gc - rc;
  791.          *ph = *ph / 6.0;
  792.             if (*ph < 0.0) *ph += 1.0;
  793.         }
  794.      }
  795.