home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wpobj.zip / CLRWHEEL.C < prev    next >
C/C++ Source or Header  |  1993-10-27  |  71KB  |  1,950 lines

  1.  
  2. /* Program name: ClrWheel.C   Title: A Color-Full Example:        */
  3. /*                     Using Color In Control Design    */
  4. /* OS/2    Developer Magazine, Issue:  Sept '93, page 46                   */
  5. /* Author:  Chris Andrew WordPerfect Corp.                */
  6. /*        Mark Benge     IBM Corp.                    */
  7. /*        Matt Smith     Prominare Inc.                    */
  8. /* Description:     Colour    Wheel sample control with threading.        */
  9. /*                                    */
  10. /* Program Requirements:  OS/2 2.x                    */
  11. /*              IBM C    Set/2                    */
  12. /*              WATCOM C 386/9.0                */
  13. /*              Borland C++ for OS/2                */
  14. /*              Zortech C++ for OS/2                */
  15. /*              OS/2 Toolkit                    */
  16.  
  17. /************************************************************************/
  18. /************************************************************************/
  19. /*               DISCLAIMER OF WARRANTIES.            */
  20. /************************************************************************/
  21. /************************************************************************/
  22. /*     The following [enclosed]    code is    library    code created by    the    */
  23. /*     authors.     This source code is  provided to you solely        */
  24. /*     for the purpose of assisting you    in the development of your    */
  25. /*     applications.  The code is provided "AS IS", without        */
  26. /*     warranty    of any kind.  The authors shall    not be liable        */
  27. /*     for any damages arising out of your use of the library code,    */
  28. /*     even if they have been advised of the possibility of such    */
  29. /*     damages.                                */
  30. /************************************************************************/
  31. /************************************************************************/
  32.     
  33. #define    INCL_DOS           /* Include OS/2 DOS Kernal        */
  34. #define    INCL_GPI           /* Include OS/2 PM GPI Interface    */
  35. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  36.  
  37. static char *MODID = "@(#)clrwheel.c:2.01";
  38.  
  39. #include <memory.h>
  40. #include <math.h>
  41. #include <os2.h>
  42. #include <stdlib.h>
  43.  
  44. #include "pdsctls.h"
  45.  
  46. /* Equivalent command line invocation (C Set++):            */
  47. /*                                    */
  48. /*     Icc -C -G3e -O+ -W3 ClrWheel.C                    */
  49.  
  50. /* Filename:   ClrWheel.C                        */
  51.  
  52. /*  Version:   2.10                            */
  53. /*  Created:   1992-11-28                        */
  54. /*  Revised:   1993-03-02                        */
  55.  
  56. /* Routines:   LONG lHSBtoRGB(LONG lHue, LONG lSaturation);        */
  57. /*           HBITMAP hbmCreateBitmap(PCLRWHEEL pcw);            */
  58. /*           VOID DrawClrWheel(HPS hPS, PCLRWHEEL pcw);        */
  59. /*           VOID _System BitmapConstructThread(PCLRWHEEL pcw);    */
  60. /*           MRESULT EXPENTRY    ClrWheelWndProc(HWND hWnd, ULONG msg,    */
  61. /*                        MPARAM mp1, MPARAM mp2);*/
  62.  
  63.  
  64. /************************************************************************/
  65. /************************************************************************/
  66. /*                                    */
  67. /* Styles supported:                            */
  68. /*                                    */
  69. /*     CWS_SOLIDCLR    : Uses solid colours when rendering        */
  70. /*     CWS_HSB           : Colour    Notification in    HSB            */
  71. /*             CWN_HSBCLRSELECTED                */
  72. /*     CWS_RGB           : Colour    Notification in    RGB            */
  73. /*             CWN_RGBCLRSELECTED                */
  74. /*     CWS_BITMAP      : Use bitmap for    render image of    wheel        */
  75. /*     CWS_AUTOSIZE    : Radius    determined by control            */
  76. /*     CWS_THREADED    : Use threading when creating bitmap        */
  77. /*                                    */
  78. /* Notification    messages:                        */
  79. /*                                    */
  80. /*     CWN_RGBCLRSELECTED : mp2    : RGB2 Value                */
  81. /*       RGB colour selected (based on style CWS_RGB)            */
  82. /*     CWN_HSBCLRSELECTED : mp2    : Low Short = Hue     (Angle)    */
  83. /*                  Hi  Short = Saturation (Radius)    */
  84. /*       HSB colour selected (based on style CWS_HSB)            */
  85. /*     CWN_XHAIRSELECTED  : mp2    : 0L                    */
  86. /*       Cross hair selected (button 1 down event)            */
  87. /*     CWN_XHAIRRELEASED  : mp2    : 0L                    */
  88. /*       Cross hair released (button 1 up event)            */
  89. /*                                    */
  90. /* Control messages:                            */
  91. /*                                    */
  92. /*     CWM_QUERYXHAIR       : Query cross hair location            */
  93. /*       Input:                            */
  94. /*           mp1 = 0L;                        */
  95. /*           mp2 = 0L;                        */
  96. /*       Ouptut:                            */
  97. /*           x = SHORT1FROMMR(mr);                */
  98. /*           y = SHORT2FROMMR(mr);                */
  99. /*     CWM_SETXHAIR       : Set cross hair location            */
  100. /*       Input:                            */
  101. /*           mp1 = x;                        */
  102. /*           mp2 = y;                        */
  103. /*       Ouptut:                            */
  104. /*           mr =    TRUE  :    position accepted and cross hair    */
  105. /*                updated                    */
  106. /*           mr =    FALSE :    invalid    position specified, cross hair    */
  107. /*                not updated                */
  108. /*     CWM_QUERYRGBCLR       : Query current RGB colour under cross hair    */
  109. /*       Input:                            */
  110. /*           mp1 = 0L;                        */
  111. /*           mp2 = 0L;                        */
  112. /*       Ouptut:                            */
  113. /*           mr =    RGB2 rgb2  : RGB Colour                */
  114. /*     CWM_SETRGBCLR       : Set cross hair location using RGB colour    */
  115. /*       Input:                            */
  116. /*           mp1 = RGB2 rgb2;                    */
  117. /*           mp2 = 0L;                        */
  118. /*       Ouptut:                            */
  119. /*           x = SHORT1FROMMR(mr);                */
  120. /*           y = SHORT2FROMMR(mr);                */
  121. /*     CWM_QUERYHSBCLR       : Query current RGB colour under cross hair    */
  122. /*       Input:                            */
  123. /*           mp1 = 0L;                        */
  124. /*           mp2 = 0L;                        */
  125. /*       Ouptut:                            */
  126. /*           sHue           = SHORT1FROMMR(mr);            */
  127. /*           sSaturation = SHORT2FROMMR(mr);            */
  128. /*     CWM_SETHSBCLR       : Set cross hair location using HSB colour    */
  129. /*       Input:                            */
  130. /*           mp1 = lHue;                        */
  131. /*           mp2 = lSaturation;                    */
  132. /*       Ouptut:                            */
  133. /*           x = SHORT1FROMMR(mr);                */
  134. /*           y = SHORT2FROMMR(mr);                */
  135. /*                                    */
  136. /************************************************************************/
  137. /************************************************************************/
  138.  
  139. LONG    lHSBtoRGB(LONG lHue, LONG lSaturation);
  140. HBITMAP    hbmCreateBitmap(PCLRWHEEL pcw);
  141. VOID    DrawClrWheel(HPS hPS, PCLRWHEEL    pcw);
  142. VOID    _System    BitmapConstructThread(PCLRWHEEL    pcw);
  143.  
  144. #pragma    subtitle("   Colour Wheel - HSB to RGB Conversion Function")
  145. #pragma    page( )
  146.  
  147. /* --- lHSBtoRGB --------------------------------------    [ Private ] ---    */
  148. /*                                    */
  149. /*     This function is    used to    determine the RGB value    for a given    */
  150. /*     hue and saturation.  The    function is based upon the algorithm    */
  151. /*     presented in the    Foly and van Dam book "Computer Graphics:       */
  152. /*     Principles and Practice" Second Addition, page 593 Figure        */
  153. /*     13.34.  The routine has been adapted to ignore the brightness    */
  154. /*     since it    will be    constant within    this implementation.        */
  155. /*     The Hue value corresponds to the    angle and the Saturation    */
  156. /*     corresponds to the radius of the    circle.     The Hue value is    */
  157. /*     from 0 to 360° and the Saturation value is from 0 to 100.  The    */
  158. /*     RGB values are defined by the system to be from 0 to 255.    */
  159. /*                                    */
  160. /*     Upon Entry:                            */
  161. /*                                    */
  162. /*     LONG lHue;     = Hue Value                    */
  163. /*     LONG lSaturation; = Saturation Value                */
  164. /*                                    */
  165. /*     Upon Exit:                            */
  166. /*                                    */
  167. /*     lHSBtoRGB = Resultant RGB Colour                    */
  168. /*                                    */
  169. /* --------------------------------------------------------------------    */
  170.  
  171. LONG lHSBtoRGB(LONG lHue, LONG lSaturation)
  172.  
  173. {
  174. RGB2   rgb2;               /* RGB Colour Holder            */
  175. PLONG  plClr = (PLONG)&rgb2;       /* Long Pointer to RGB Colour Holder    */
  176.         
  177.                /* Initialize the options component of the RGB    */
  178.                /* holder since it is a reserved    value        */
  179. rgb2.fcOptions = 0;
  180.                /* Check    to see if the saturation level is 0    */
  181.                /* in which case    the colour should be white    */
  182. if ( lSaturation == 0 )
  183.    {
  184.    rgb2.bRed   =
  185.    rgb2.bBlue  =
  186.    rgb2.bGreen = 255;
  187.    }
  188. else
  189.    {
  190.                /* Check    to see if the hue is at    its maximum    */
  191.                /* value    in which case the hue should revert to    */
  192.                /* its lower limit                */
  193.    if (    lHue ==    360L )
  194.        lHue = 0L;
  195.                /* Break    the hue    into 6 wedges which corresponds    */
  196.                /* to red, yellow, green, cyan, blue and    magenta    */
  197.    switch ( lHue / 60L )
  198.        {
  199.                /* Red wedge                    */
  200.        case 0 :
  201.        rgb2.bRed   = (BYTE)255;
  202.        rgb2.bGreen = (BYTE)((((100 - ((lSaturation * (100 -    ((lHue % 60L) *    100L) /    60)) / 100L))) * 255L) / 100L);
  203.        rgb2.bBlue  = (BYTE)(((100 -    lSaturation) * 255L) / 100L);
  204.        break;
  205.                /* Yellow wedge                    */
  206.        case 1 :
  207.        rgb2.bRed   = (BYTE)((((100 - ((lSaturation * ((lHue    % 60L) * 100L) / 60) / 100L))) * 255L) / 100L);
  208.        rgb2.bGreen = (BYTE)255;
  209.        rgb2.bBlue  = (BYTE)(((100 -    lSaturation) * 255L) / 100L);
  210.        break;
  211.                /* Green    wedge                    */
  212.        case 2 :
  213.        rgb2.bRed   = (BYTE)(((100 -    lSaturation) * 255L) / 100L);
  214.        rgb2.bGreen = (BYTE)255;
  215.        rgb2.bBlue  = (BYTE)((((100 - ((lSaturation * (100 -    ((lHue % 60L) *    100L) /    60)) / 100L))) * 255L) / 100L);
  216.        break;
  217.                /* Cyan wedge                    */
  218.        case 3 :
  219.        rgb2.bRed   = (BYTE)(((100 -    lSaturation) * 255L) / 100L);
  220.        rgb2.bGreen = (BYTE)((((100 - ((lSaturation * ((lHue    % 60L) * 100L) / 60) / 100L))) * 255L) / 100L);
  221.        rgb2.bBlue  = (BYTE)255;
  222.        break;
  223.                /* Blue wedge                    */
  224.        case 4 :
  225.        rgb2.bRed   = (BYTE)((((100 - ((lSaturation * (100 -    ((lHue % 60L) *    100L) /    60)) / 100L))) * 255L) / 100L);
  226.        rgb2.bGreen = (BYTE)(((100 -    lSaturation) * 255L) / 100L);
  227.        rgb2.bBlue  = (BYTE)255;
  228.        break;
  229.                /* Magenta wedge                    */
  230.        case 5 :
  231.        rgb2.bRed   = (BYTE)255;
  232.        rgb2.bGreen = (BYTE)(((100 -    lSaturation) * 255L) / 100L);
  233.        rgb2.bBlue  = (BYTE)((((100 - ((lSaturation * ((lHue    % 60L) * 100L) / 60) / 100L))) * 255L) / 100L);
  234.        break;
  235.        }
  236.    }
  237. return(*plClr);
  238. }
  239. #pragma    subtitle("   Colour Wheel - Control Window Bitmap Image Procedure")
  240. #pragma    page( )
  241.  
  242. /* --- hbmCreateBitmap --------------------------------    [ Private ] ---    */
  243. /*                                    */
  244. /*     This function is    used to    calculate and create the bitmap        */
  245. /*     storage for both    the main Client    and Context Windows.        */
  246. /*                                    */
  247. /*     Upon Entry:                            */
  248. /*                                    */
  249. /*     PCLRWHEEL pcw; =    Colour Wheel Data Pointer            */
  250. /*                                    */
  251. /*     Upon Exit:                            */
  252. /*                                    */
  253. /*     hbmCreateBitmap = NULL :    Error, Bitmap Not Created        */
  254. /*               =      :    Bitmap Created                */
  255. /*                                    */
  256. /* --------------------------------------------------------------------    */
  257.  
  258. HBITMAP    hbmCreateBitmap(PCLRWHEEL pcw)
  259.  
  260. {
  261. BITMAPINFOHEADER2 bminfo2;       /* Bitmap Information Header        */
  262. HDC          hDC;           /* Device Context Handle        */
  263. SIZEL          sizl;           /* Sizing Structure            */
  264. PLONG          plFormats;       /* Formats Array            */
  265. LONG          cFormats;       /* Formats Count            */
  266.  
  267. if ( pcw->hbmConstruct )
  268.    GpiDeleteBitmap(pcw->hbmConstruct);
  269.  
  270.                /* Get bitmap device context handle for the main    */
  271.                /* Client Window                    */
  272.  
  273. if ( !(hDC = DevOpenDC((HAB)NULL, OD_MEMORY, "*", 0L, 0L, 0L)) )
  274.    return((HBITMAP)NULL);
  275.                /* Create bitmap    presentation space specifying    */
  276.                /* entire map Client Window for size required    */
  277. sizl.cx    = pcw->cx;
  278. sizl.cy    = pcw->cy;
  279.  
  280. if ( !(pcw->hpsBitmap =    GpiCreatePS((HAB)NULL, hDC, &sizl, PU_PELS | GPIT_NORMAL | GPIA_ASSOC))    )
  281.    {
  282.                /* Error    occurred during    creation of        */
  283.                /* presentation space, close device context    */
  284.    DevCloseDC(hDC);
  285.    return((HBITMAP)NULL);
  286.    }
  287.                /* Check    to see if the device capabilities for    */
  288.                /* the number of    planes and bitcounts have been    */
  289.                /* determined yet on a previous pass through    */
  290.                /* this routine and if they haven't, get them    */
  291. if ( pcw->cPlanes == 0 )
  292.    {
  293.                /* Get the number of bitmap formats that    the    */
  294.                /* display driver supports            */
  295.  
  296.    DevQueryCaps(hDC, CAPS_BITMAP_FORMATS, 1L, &cFormats);
  297.  
  298.                /* Allocate memory for the formats array        */
  299.  
  300.    DosAllocMem((PPVOID)&plFormats, 2UL * cFormats,
  301.            PAG_READ    | PAG_WRITE | PAG_COMMIT);
  302.  
  303.                /* Get the bitmap display formats.  The first    */
  304.                /* set within the array will be the one that    */
  305.                /* most closely matches the display device.    */
  306.  
  307.    GpiQueryDeviceBitmapFormats(pcw->hpsBitmap, cFormats    * 2L, plFormats);
  308.  
  309.    pcw->cPlanes      = plFormats[0];
  310.    pcw->cBitCount = plFormats[1];
  311.  
  312.                /* Release the memory allocated for the bitmap    */
  313.                /* formats array                    */
  314.  
  315.    DosFreeMem((PVOID)plFormats);
  316.    }
  317.                /* Create actual    bitmap storage for colour wheel    */
  318.                /* having the default plane and bit count    */
  319.  
  320. memset(&bminfo2, 0, sizeof(BITMAPINFOHEADER2));
  321. bminfo2.cbFix      = sizeof(BITMAPINFOHEADER2);
  322. bminfo2.cx      = pcw->cx;
  323. bminfo2.cy      = pcw->cy;
  324. bminfo2.cPlanes      = pcw->cPlanes;
  325. bminfo2.cBitCount = pcw->cBitCount;
  326.  
  327. if ( !(pcw->hbmConstruct = GpiCreateBitmap(pcw->hpsBitmap, &bminfo2, 0L, 0L, 0L)) )
  328.    {
  329.                /* Error    occurred during    creation of bitmap    */
  330.                /* storage, destroy presentation    space created    */
  331.                /* and close device context opened        */
  332.  
  333.    GpiDestroyPS(pcw->hpsBitmap);
  334.    DevCloseDC(hDC);
  335.    return((HBITMAP)NULL);
  336.    }
  337.                /* Set bitmap as    current    bitmap to use        */
  338.  
  339. GpiSetBitmap(pcw->hpsBitmap, pcw->hbmConstruct);
  340.  
  341.                /* Draw the colour wheel                */
  342.  
  343. DrawClrWheel(pcw->hpsBitmap, pcw);
  344.  
  345.                /* Set the bitmap to allow completion of    bitmap    */
  346.                /* in memory                    */
  347.  
  348. GpiSetBitmap(pcw->hpsBitmap, (HDC)NULL);
  349.  
  350.                /* Destroy the memory device context        */
  351.  
  352. GpiAssociate(pcw->hpsBitmap, (HDC)NULL);
  353.  
  354.                /* Destroy the presentation spaces used        */
  355.  
  356. GpiDestroyPS(pcw->hpsBitmap);
  357. DevCloseDC(hDC);
  358. pcw->hpsBitmap = (HPS)NULL;
  359.  
  360.                /* Return the bitmap handle that    will be    used in    */
  361.                /* painting the image on    the window        */
  362. return(pcw->hbmConstruct);
  363.  
  364. }
  365. #pragma    subtitle("   Colour Wheel - Control Window Procedure")
  366. #pragma    page( )
  367.  
  368. /* --- DrawClrWheel -----------------------------------    [ Private ] ---    */
  369. /*                                    */
  370. /*     This function is    used to    draw the actual    colour wheel based    */
  371. /*     on the parameters defined for the wheel.     It should be noted    */
  372. /*     that all    angles when used with sin and cosine functions are    */
  373. /*     are in radians.                            */
  374. /*                                    */
  375. /*     Upon Entry:                            */
  376. /*                                    */
  377. /*     HPS     hPS; =    Presentation Space Handle            */
  378. /*     PCLRWHEEL pcw; =    Colour Wheel Data Pointer            */
  379. /*                                    */
  380. /*     Upon Exit:                            */
  381. /*                                    */
  382. /*     Nothing                                */
  383. /*                                    */
  384. /* --------------------------------------------------------------------    */
  385.  
  386. VOID DrawClrWheel(HPS hPS, PCLRWHEEL pcw)
  387.  
  388. {
  389. ARCPARAMS ap;               /* Arc Parameters            */
  390. LONG      cIncrements;           /* Increments Count            */
  391. LONG      lSector;           /* Sector                */
  392. PLONG      plClr;           /* RGB2 Colour Pointer        */
  393. POINTL      ptl;               /* Display Point            */
  394. POINTL      ptlCurrent;           /* Display Point            */
  395. RGB2      rgb2;               /* RGB2 Colour Holder        */
  396. double rdAngle;               /* Angle                */
  397. register INT cAngle, cSaturation;  /* Loop Counter            */
  398. register INT i;               /* Loop Counter            */
  399.  
  400.                /* Set the background of    the control to the    */
  401.                /* dialogue background colour            */
  402.  
  403. WinFillRect(hPS, &pcw->rcl, SYSCLR_FIELDBACKGROUND);
  404.  
  405.                /* Set the colour table to RGB mode        */
  406.  
  407. GpiCreateLogColorTable(hPS, pcw->ulOptions, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  408.  
  409.                /* Point    to the RGB holder since    the colour    */
  410.                /* setting function doesn't like the RGB2        */
  411.                /* structure being specified            */
  412. plClr =    (PLONG)&rgb2;
  413.                /* Initialize the reserved field    of the RGB2    */
  414.                /* structure                    */
  415. rgb2.fcOptions = 0;
  416.                /* Calculate the    shift value of the saturation    */
  417.                /* increment                    */
  418.  
  419. cIncrements = 100L / pcw->lSaturationInc;
  420.  
  421.                /* Moving through a full    circle,    create the    */
  422.                /* colour wheel.     The method used here is to    */
  423.                /* move through each degree and display each    */
  424.                /* saturation slice of the degree pie.  It    */
  425.                /* should be noted that the saturaction moves    */
  426.                /* from the outside of the circle to the    centre    */
  427.                /* point    when drawing.                */
  428.  
  429. for ( cAngle = 0; cAngle < 360;    cAngle += pcw->lAngle )
  430.    {
  431.                /* Break    the wheel into 6 wedges    which        */
  432.                /* corresponds to red, yellow, green, cyan, blue    */
  433.                /* and magenta                    */
  434.  
  435.    switch ( lSector = cAngle / 60L )
  436.        {
  437.                /* Red wedge                    */
  438.        case 0 :
  439.        rgb2.bRed   = (BYTE)255;
  440.        break;
  441.                /* Yellow wedge                    */
  442.        case 1 :
  443.        rgb2.bGreen = (BYTE)255;
  444.        break;
  445.                /* Green    wedge                    */
  446.        case 2 :
  447.        rgb2.bGreen = (BYTE)255;
  448.        break;
  449.                /* Cyan wedge                    */
  450.        case 3 :
  451.        rgb2.bBlue  = (BYTE)255;
  452.        break;
  453.                /* Blue wedge                    */
  454.        case 4 :
  455.        rgb2.bBlue  = (BYTE)255;
  456.        break;
  457.                /* Magenta wedge                    */
  458.        case 5 :
  459.        rgb2.bRed   = (BYTE)255;
  460.        break;
  461.        }
  462.  
  463.    for ( i = 1,    cSaturation = pcw->lSaturationInc; i <=    cIncrements; cSaturation += pcw->lSaturationInc, i++ )
  464.        {
  465.                /* Break    the wheel into 6 wedges    which        */
  466.                /* corresponds to red, yellow, green, cyan, blue    */
  467.                /* and magenta                    */
  468.  
  469.        switch (    lSector    )
  470.        {
  471.                /* Red wedge                    */
  472.        case    0 :
  473.            rgb2.bGreen = (BYTE)((((100 - ((cSaturation * (100 - ((cAngle % 60L) * 100L) / 60)) / 100L))) * 255L) / 100L);
  474.            rgb2.bBlue  = (BYTE)(((100 - cSaturation) * 255L) / 100L);
  475.            break;
  476.                /* Yellow wedge                    */
  477.        case    1 :
  478.            rgb2.bRed   = (BYTE)((((100 - ((cSaturation * ((cAngle %    60L) * 100L) / 60) / 100L))) * 255L) / 100L);
  479.            rgb2.bBlue  = (BYTE)(((100 - cSaturation) * 255L) / 100L);
  480.            break;
  481.                /* Green    wedge                    */
  482.        case    2 :
  483.            rgb2.bRed   = (BYTE)(((100 - cSaturation) * 255L) / 100L);
  484.            rgb2.bBlue  = (BYTE)((((100 - ((cSaturation * (100 - ((cAngle % 60L) * 100L) / 60)) / 100L))) * 255L) / 100L);
  485.            break;
  486.                /* Cyan wedge                    */
  487.        case    3 :
  488.            rgb2.bRed   = (BYTE)(((100 - cSaturation) * 255L) / 100L);
  489.            rgb2.bGreen = (BYTE)((((100 - ((cSaturation * ((cAngle %    60L) * 100L) / 60) / 100L))) * 255L) / 100L);
  490.            break;
  491.                /* Blue wedge                    */
  492.        case    4 :
  493.            rgb2.bRed   = (BYTE)((((100 - ((cSaturation * (100 - ((cAngle % 60L) * 100L) / 60)) / 100L))) * 255L) / 100L);
  494.            rgb2.bGreen = (BYTE)(((100 - cSaturation) * 255L) / 100L);
  495.            break;
  496.                /* Magenta wedge                    */
  497.        case    5 :
  498.            rgb2.bGreen = (BYTE)(((100 - cSaturation) * 255L) / 100L);
  499.            rgb2.bBlue  = (BYTE)((((100 - ((cSaturation * ((cAngle %    60L) * 100L) / 60) / 100L))) * 255L) / 100L);
  500.            break;
  501.        }
  502.                /* Set the colour for the wedge saturation being    */
  503.                /* drawn                        */
  504.  
  505.        GpiSetColor(hPS,    *plClr);
  506.             
  507.                /* The method that the wedge saturation is drawn    */
  508.                /* is to    first draw the outer curve with    the    */
  509.                /* lower    curve right corner being the line    */
  510.                /* start.  The location where the upper curve    */
  511.                /* ends is determined to    allow for proper area    */
  512.                /* closure when the lower curve is drawn.  This    */
  513.                /* lower    curve is drawn withou a    line, namely,    */
  514.                /* the line start position is the same point as    */
  515.                /* the curve start position.  When the arc has    */
  516.                /* been drawn for the lower curve, a line from    */
  517.                /* that ending point to upper curve ending point    */
  518.                /* is drawn and the area    is closed thereby    */
  519.                /* allowing the correct area fill in the    desired    */
  520.                /* RGB colour.                    */
  521.  
  522.                /* Start    the area braket                */
  523.  
  524.        GpiBeginArea(hPS, BA_NOBOUNDARY | BA_ALTERNATE);
  525.  
  526.                /* Set the arc radius to    the current saturation    */
  527.                /* value                        */
  528.  
  529.        if ( i == cIncrements )
  530.                /* Set the arc radius to    the current saturation    */
  531.                /* value                        */
  532.  
  533.        pcw->ap.lP =    pcw->ap.lQ = pcw->lRadius;
  534.        else
  535.        pcw->ap.lP =    pcw->ap.lQ = (i    * pcw->lSaturationInc *    pcw->lRadius) /    100L;
  536.        GpiSetArcParams(hPS, &pcw->ap);
  537.  
  538.        if ( i == 1 )
  539.        {
  540.        GpiMove(hPS,    &pcw->ptlOrigin);
  541.  
  542.                /* Draw the outside arc                */
  543.  
  544.        GpiPartialArc(hPS, &pcw->ptlOrigin, MAKEFIXED(1, 0),
  545.              MAKEFIXED(cAngle, 0), MAKEFIXED(pcw->lAngle, 0));
  546.  
  547.                /* Draw the closure line    from the ending    point    */
  548.                /* of the inner arc to the ending point of the    */
  549.                /* outer    arc and    close the area braket forcing    */
  550.                /* the colour fill of the area drawn in the    */
  551.                /* saturation colour.                */
  552.  
  553.        GpiLine(hPS,    &pcw->ptlOrigin);
  554.        ap =    pcw->ap;
  555.        }
  556.        else
  557.        {
  558.        ptl.x = (LONG)((double)ap.lQ    * cos(rdAngle =    (double)cAngle / 57.29577951)) + pcw->ptlOrigin.x;
  559.        ptl.y = (LONG)((double)ap.lQ    * sin(rdAngle))    + pcw->ptlOrigin.y;
  560.  
  561.        GpiMove(hPS,    &ptl);
  562.  
  563.                /* Draw the outside arc                */
  564.  
  565.        GpiPartialArc(hPS, &pcw->ptlOrigin, MAKEFIXED(1, 0),
  566.              MAKEFIXED(cAngle, 0), MAKEFIXED(pcw->lAngle, 0));
  567.  
  568.                /* Get the ending location of arc to allow for    */
  569.                /* later    closure    of the area            */
  570.  
  571.        GpiQueryCurrentPosition(hPS,    &ptlCurrent);
  572.  
  573.                /* Set the inner    arc radius and move back to the    */
  574.                /* calculated starting location            */
  575.  
  576.        GpiSetArcParams(hPS,    &ap);
  577.        GpiMove(hPS,    &ptl);
  578.  
  579.                /* Draw the inner arc                */
  580.  
  581.        GpiPartialArc(hPS, &pcw->ptlOrigin, MAKEFIXED(1, 0),
  582.              MAKEFIXED(cAngle, 0), MAKEFIXED(pcw->lAngle, 0));
  583.  
  584.                /* Draw the closure line    from the ending    point    */
  585.                /* of the inner arc to the ending point of the    */
  586.                /* outer    arc and    close the area braket forcing    */
  587.                /* the colour fill of the area drawn in the    */
  588.                /* saturation colour.                */
  589.  
  590.        GpiLine(hPS,    &ptlCurrent);
  591.        ap =    pcw->ap;
  592.        }
  593.       GpiEndArea(hPS);
  594.       }
  595.    if (    pcw->tid && GpiQueryStopDraw(hPS) )
  596.        break;
  597.    }
  598. }
  599. #pragma    subtitle("   Colour Wheel - Control Window Procedure")
  600. #pragma    page( )
  601.  
  602. /* --- BitmapConstructThread --------------------------    [ Private ] ---    */
  603. /*                                    */
  604. /*     This function is    used to    process    the messages for the Colour    */
  605. /*     Wheel control window.  It should    be noted that all angles    */
  606. /*     when used with sin and cosine functions are in radians.        */
  607. /*                                    */
  608. /*     Upon Entry:                            */
  609. /*                                    */
  610. /*     ULONG ulParm; = Thread Parameter                    */
  611. /*                                    */
  612. /*     Upon Exit:                            */
  613. /*                                    */
  614. /*     Nothing                                */
  615. /*                                    */
  616. /* --------------------------------------------------------------------    */
  617.  
  618. VOID _System BitmapConstructThread(PCLRWHEEL pcw)
  619.  
  620. {
  621. HAB habThread;               /* Thread Anchor Block        */
  622.  
  623.                /* Register the thread with OS/2    PM        */
  624.  
  625. habThread = WinInitialize(0);
  626.  
  627.                /* Create the bitmap using the passed parameter    */
  628.                /* to the thread    as the address to the defined    */
  629.                /* colour wheel data                */
  630.  
  631. if ( pcw->hbm =    hbmCreateBitmap(pcw) )
  632.    {
  633.    pcw->hbmConstruct = 0L;
  634.  
  635.                /* Clear    the thread ID to allow the allow    */
  636.                /* routines to become active.  The thread ID is    */
  637.                /* used as a form of semaphore.            */
  638.    pcw->tid = 0L;
  639.  
  640.                /* Bitmap successfully created, force the    */
  641.                /* painting of the wheel    within the control    */
  642.                /* rectangle                    */
  643.  
  644.    WinInvalidateRect(pcw->hWnd,    NULL, FALSE);
  645.    }
  646. else
  647.                /* Clear    the thread ID to allow the allow    */
  648.                /* routines to become active.  The thread ID is    */
  649.                /* used as a form of semaphore.            */
  650.    pcw->tid = 0L;
  651.                /* De-register the thread with OS/2 PM since the    */
  652.                /* creation of the bitmap is complete        */
  653. WinTerminate(habThread);
  654.                /* Exit the thread                */
  655. DosExit(EXIT_THREAD, 0L);
  656. }
  657. #pragma    subtitle("   Colour Wheel - Control Window Procedure")
  658. #pragma    page( )
  659.  
  660. /* --- ClrWheelWndProc ------------------------------------------------    */
  661. /*                                    */
  662. /*     This function is    used to    process    the messages for the Colour    */
  663. /*     Wheel control window.  It should    be noted that all angles    */
  664. /*     when used with sin and cosine functions are in radians.        */
  665. /*                                    */
  666. /*     Upon Entry:                            */
  667. /*                                    */
  668. /*     HWND   hWnd; = Window Handle                    */
  669. /*     ULONG  msg;  = PM Message                    */
  670. /*     MPARAM mp1;  = Message Parameter    1                */
  671. /*     MPARAM mp2;  = Message Parameter    2                */
  672. /*                                    */
  673. /*     Upon Exit:                            */
  674. /*                                    */
  675. /*     ClrWheelWndProc = Message Handling Result            */
  676. /*                                    */
  677. /* --------------------------------------------------------------------    */
  678.  
  679. MRESULT    EXPENTRY ClrWheelWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  680.  
  681. {
  682. BOOL          fReturn;           /* Message Return Flag        */
  683. HPS          hPS;           /* Presentation Space Handle        */
  684. LONG          lMax;           /* Maximum Value            */
  685. LONG          lMin;           /* Minimum Value            */
  686. LONG          lAngle;           /* Angle Holder            */
  687. LONG          lRadius;           /* Radius Holder            */
  688. PCLRWHEEL     pcw;           /* Colour Wheel Internal Data Pointer*/
  689. PCLRWHLCDATA  pcwd;           /* Colour Wheel Data    Pointer        */
  690. PCREATESTRUCT pcrst;           /* Create Structure Pointer        */
  691. POINTL          ptl;           /* Display Point            */
  692. RECTL          rcl;           /* Client Window Rectangle        */
  693. PRGB2          prgb2;           /* RGB2 Structure Pointer        */
  694. double          rdAngle;           /* Angle                */
  695. register INT x,    y;           /* Loop Counter            */
  696.  
  697. switch ( msg )
  698.    {
  699.  
  700. /************************************************************************/
  701. /************************************************************************/
  702. /*                                    */
  703. /* Part    1: Control creation coding                    */
  704. /*                                    */
  705. /************************************************************************/
  706. /************************************************************************/
  707.  
  708.    /*********************************************************************/
  709.    /*  Control creation                            */
  710.    /*********************************************************************/
  711.  
  712.    case    WM_CREATE :
  713.                /* Get the address of the CTLDATA structure that    */
  714.                /* may contain the bitmap information that the    */
  715.                /* control can use during its creation instead    */
  716.                /* of using messages to set the button images    */
  717.  
  718.        if ( pcwd = (PCLRWHLCDATA)PVOIDFROMMP(mp1) )
  719.  
  720.                /* Check    to see that the    structure passed is    */
  721.                /* what is expected and if not, return        */
  722.                /* indicating that the control window should    */
  723.                /* not be further created            */
  724.  
  725.                /*************************************************/
  726.                /*  NOTE:   OS/2    2.0 requires the first element    */
  727.                /*       of the CTLDATA structure to be the    */
  728.                /*       size    of the structure and this    */
  729.                /*       value must be less than 64 KB    */
  730.                /*************************************************/
  731.  
  732.        if (    (pcwd->cb != sizeof(CLRWHLCDATA)) )
  733.            return(MRFROMLONG(TRUE));
  734.  
  735.                /* Allocate memory for internal control data    */
  736.  
  737.        DosAllocMem((PPVOID)&pcw, sizeof(CLRWHEEL),
  738.            PAG_READ | PAG_WRITE    | PAG_COMMIT);
  739.  
  740.                /* Save the address of the internal control data    */
  741.                /* in the control's reserved memory to allow it  */
  742.                /* to be    referenced as required by the control    */
  743.  
  744.        WinSetWindowPtr(hWnd, QUCWP_WNDP, (PVOID)pcw);
  745.  
  746.                /* Get the control's creation structure address  */
  747.                /* to copy the relevant information such    as the    */
  748.                /* size,    position and text of the control into    */
  749.                /* the internal control data            */
  750.  
  751.        pcrst = (PCREATESTRUCT)PVOIDFROMMP(mp2);
  752.  
  753.                /* Save the owner and parent of the control so    */
  754.                /* notification messages    can be sent back to    */
  755.                /* the proper locations within the owning    */
  756.                /* application                    */
  757.  
  758.        pcw->hWnd       = hWnd;
  759.        pcw->hwndOwner  = pcrst->hwndOwner;
  760.        pcw->hwndParent = pcrst->hwndParent;
  761.  
  762.                /* Save the ID of the control, style and    save    */
  763.                /* the default style along with the normal    */
  764.                /* arrow    pointer    handle which will be used when    */
  765.                /* the pointer passes over the control        */
  766.  
  767.        pcw->id           = pcrst->id;
  768.        pcw->flStyle    = pcrst->flStyle;
  769.        pcw->hptrArrow  = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW,
  770.                         FALSE);
  771.  
  772.                /* Check    to see if the style for    the control    */
  773.                /* indicates that pure colours (solid) should    */
  774.                /* be used                    */
  775.  
  776.        if ( pcrst->flStyle & CWS_SOLIDCLR )
  777.        pcw->ulOptions = LCOL_PURECOLOR;
  778.  
  779.                /* Save the initial size    of the control        */
  780.  
  781.        pcw->rcl.xRight    = pcrst->cx;
  782.        pcw->rcl.yTop    = pcrst->cy;
  783.        pcw->cx        = pcrst->cx;
  784.        pcw->cy        = pcrst->cy;
  785.  
  786.                /* Save the co-ordinates    of the rectangle for    */
  787.                /* the bitmap display if    it is required        */
  788.  
  789.        pcw->aptl[1].x =    pcw->aptl[3].x = pcrst->cx - 1L;
  790.        pcw->aptl[1].y =    pcw->aptl[3].y = pcrst->cy - 1L;
  791.  
  792.                /* Calculate the    origin point for the circle    */
  793.  
  794.        pcw->ptlOrigin.x    = (pcrst->cx - 2L) / 2L;
  795.        pcw->ptlOrigin.y    = (pcrst->cy - 2L) / 2L;
  796.  
  797.        pcw->aptlXHair[0].x = 0L;
  798.        pcw->aptlXHair[0].y = pcw->ptlOrigin.y;
  799.        pcw->aptlXHair[1].x = pcrst->cx - 1L;
  800.        pcw->aptlXHair[1].y = pcw->ptlOrigin.y;
  801.        pcw->aptlXHair[2].x = pcw->ptlOrigin.x;
  802.        pcw->aptlXHair[2].y = 0L;
  803.        pcw->aptlXHair[3].x = pcw->ptlOrigin.x;
  804.        pcw->aptlXHair[3].y = pcw->cy - 1L;
  805.  
  806.                /* Determine if CTLDATA was specified for the    */
  807.                /* control and if the case, get the data    and    */
  808.                /* set up the control internal values        */
  809.        if ( pcwd )
  810.        {
  811.                /* Determine if the angle is within the defined    */
  812.                /* range    for the    colour wheel            */
  813.  
  814.        if (    (pcwd->lAngle <    1L) || (pcwd->lAngle > 45L)  )
  815.  
  816.                /* Specified angle for the wedges is outside    */
  817.                /* the defined limits for the colour wheel, set    */
  818.                /* the angle to the default value of 10°        */
  819.  
  820.            pcw->lAngle = 10L;
  821.        else
  822.                /* Valid    value specified, save the angle        */
  823.                /* within the internal data structure        */
  824.  
  825.            pcw->lAngle = pcwd->lAngle;
  826.  
  827.                /* Determine if the saturation increment    outside    */
  828.                /* the defined limits for the colour wheel    */
  829.  
  830.        if (    (pcwd->lSaturationInc <    1L) || (pcwd->lSaturationInc > 25L) )
  831.  
  832.                /* Specified saturation increment outside the    */
  833.                /* defined limits for the colour    wheel, set the    */
  834.                /* saturation increment to 10            */
  835.  
  836.            pcw->lSaturationInc = 10L;
  837.        else
  838.                /* Valid    value specified, save the saturation    */
  839.                /* within the internal data structure        */
  840.  
  841.            pcw->lSaturationInc = pcwd->lSaturationInc;
  842.  
  843.                /* Determine if the radius specified is within    */
  844.                /* the limits of    the control size and is    not    */
  845.                /* negative                    */
  846.  
  847.        if (    ((pcwd->lRadius    < 1L) || (pcwd->lRadius    > pcrst->cx) ||
  848.         (pcwd->lRadius > pcrst->cy)) ||    (pcw->flStyle &    CWS_AUTOSIZE) )
  849.  
  850.                /* Invalid size given or    autosizing requested,    */
  851.                /* form the radius for the wheel            */
  852.  
  853.            if ( pcrst->cx <    pcrst->cy )
  854.            pcw->lRadius    = (pcrst->cx - 2L) / 2L;
  855.            else
  856.            pcw->lRadius    = (pcrst->cy - 2L) / 2L;
  857.        else
  858.                /* Valid    radius given, save the value internally    */
  859.  
  860.            pcw->lRadius = pcwd->lRadius;
  861.        }
  862.        else
  863.        {
  864.                /* No CTLDATA specified,    use default angle and    */
  865.                /* saturation.  For the radius, use the best    */
  866.                /* fit for the width or height            */
  867.  
  868.        pcw->lAngle           = 5;
  869.        pcw->lSaturationInc = 5;
  870.        if (    pcrst->cx < pcrst->cy )
  871.            pcw->lRadius = pcw->ptlOrigin.x;
  872.        else
  873.            pcw->lRadius = pcw->ptlOrigin.y;
  874.        }
  875.        if ( pcw->flStyle & CWS_BITMAP )
  876.        if (    pcw->flStyle & CWS_THREADED )
  877.           DosCreateThread(&pcw->tid, (PFNTHREAD)BitmapConstructThread,
  878.                   (ULONG)pcw, 2UL, 8192);
  879.        else
  880.            pcw->hbm    = hbmCreateBitmap(pcw);
  881.        break;
  882.  
  883. /************************************************************************/
  884. /************************************************************************/
  885. /*                                    */
  886. /* Part    2: Control sizing                        */
  887. /*                                    */
  888. /************************************************************************/
  889. /************************************************************************/
  890.  
  891.    /*********************************************************************/
  892.    /*  Control changing    size                        */
  893.    /*********************************************************************/
  894.  
  895.    case    WM_SIZE    :
  896.                /* Get the address of the control info from the    */
  897.                /* control's reserved memory                     */
  898.  
  899.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  900.  
  901.                /* Save the new sizes within the    control    info    */
  902.  
  903.        pcw->rcl.xRight    = SHORT1FROMMP(mp2);
  904.        pcw->rcl.yTop    = SHORT2FROMMP(mp2);
  905.        pcw->cx        = SHORT1FROMMP(mp2);
  906.        pcw->cy        = SHORT2FROMMP(mp2);
  907.        pcw->ptlOrigin.x    = SHORT1FROMMP(mp2) / 2L;
  908.        pcw->ptlOrigin.y    = SHORT2FROMMP(mp2) / 2L;
  909.  
  910.        pcw->aptl[1].x =    pcw->aptl[3].x = SHORT1FROMMP(mp2) - 1L;
  911.        pcw->aptl[1].y =    pcw->aptl[3].y = SHORT2FROMMP(mp2) - 1L;
  912.        if ( pcw->flStyle & CWS_AUTOSIZE    )
  913.        if (    pcw->cx    < pcw->cy )
  914.            pcw->lRadius = pcw->ptlOrigin.x;
  915.        else
  916.            pcw->lRadius = pcw->ptlOrigin.y;
  917.  
  918.        if ( pcw->flStyle & CWS_BITMAP )
  919.        if (    pcw->flStyle & CWS_THREADED )
  920.            {
  921.            if ( pcw->tid )
  922.            {
  923.            if (    pcw->hpsBitmap )
  924.                GpiSetStopDraw(pcw->hpsBitmap, SDW_ON);
  925.            DosKillThread(pcw->tid);
  926.            }
  927.            DosCreateThread(&pcw->tid, (PFNTHREAD)BitmapConstructThread,
  928.                    (ULONG)pcw, 2UL,    8192UL);
  929.            }
  930.        else
  931.            pcw->hbm    = hbmCreateBitmap(pcw);
  932.        break;
  933.  
  934. /************************************************************************/
  935. /************************************************************************/
  936. /*                                    */
  937. /* Part    3: Mouse input interface                    */
  938. /*                                    */
  939. /************************************************************************/
  940. /************************************************************************/
  941.  
  942.    /*********************************************************************/
  943.    /*  Mouse Button 1 selection                        */
  944.    /*********************************************************************/
  945.  
  946.    case    WM_BUTTON1DOWN :
  947.                /* Get the current mouse    pointer    position and    */
  948.                /* place    within the test    point structure        */
  949.  
  950.        ptl.x = SHORT1FROMMP(mp1);
  951.        ptl.y = SHORT2FROMMP(mp1);
  952.  
  953.                /* Get the address of the control info from the    */
  954.                /* control's reserved memory                     */
  955.  
  956.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  957.  
  958.                /* Check    to see if the colour wheel is a        */
  959.                /* threaded bitmap version, in which case differ    */
  960.                /* any mouse selections until after the bitmap    */
  961.                /* has been fully created.  The thread ID is    */
  962.                /* used as an internal semaphore            */
  963.        if ( pcw->tid )
  964.        {
  965.        WinAlarm(HWND_DESKTOP, WA_NOTE);
  966.        break;
  967.        }
  968.                /* Set up the arc parameters            */
  969.  
  970.        pcw->ap.lP = pcw->ap.lQ = pcw->lRadius;
  971.        GpiSetArcParams(hPS = WinGetPS(hWnd), &pcw->ap);
  972.  
  973.                /* Create the clipping path to encompass    just    */
  974.                /* the colour wheel itself.  To do this,    open a    */
  975.                /* normal path and draw a circle    into the path    */
  976.                /* that has the same radius as the colour wheel.    */
  977.  
  978.        GpiBeginPath(hPS, 1L);
  979.        GpiMove(hPS, &pcw->ptlOrigin);
  980.        GpiFullArc(hPS, DRO_OUTLINE, MAKEFIXED(1, 0));
  981.        GpiEndPath(hPS);
  982.                /* Circle complete, convert the normal path to a    */
  983.                /* clip path to allow the determination of the    */
  984.                /* mouse    button click within the    colour wheel or    */
  985.                /* outside the edge of the wheel    but still    */
  986.                /* within the limits of the control itself    */
  987.  
  988.        GpiSetClipPath(hPS, 1L, SCP_ALTERNATE | SCP_AND);
  989.  
  990.                /* Check    to see if the mouse pointer button    */
  991.                /* click    within the confines of the colour    */
  992.                /* wheel                        */
  993.  
  994.        if ( GpiPtVisible(hPS, &ptl) == PVIS_VISIBLE )
  995.        {
  996.                /* Mouse    click within the colour    wheel, capture    */
  997.                /* the mouse for    this control only until    the    */
  998.                /* button 1 of the mouse    is released        */
  999.  
  1000.        WinSetCapture(HWND_DESKTOP, hWnd);
  1001.        pcw->fCapture = TRUE;
  1002.  
  1003.                /* Send notification message to control owner    */
  1004.                /* that cross hair has been selected        */
  1005.                /*                        */
  1006.                /* Notification:    CWN_XHAIRSELECTED        */
  1007.                /* mp2:        N/A                */
  1008.  
  1009.        WinSendMsg(pcw->hwndOwner, WM_CONTROL,
  1010.               MPFROM2SHORT(pcw->id, CWN_XHAIRSELECTED),    0L);
  1011.  
  1012.                /* Set the mix mode for line invert        */
  1013.  
  1014.        GpiSetMix(hPS, FM_INVERT);
  1015.  
  1016.                /* Erase    the current cross hair by drawing it    */
  1017.                /* again    which will cause the previous colours    */
  1018.                /* to be    displayed since    it is being drawn in    */
  1019.                /* invert mix mode                */
  1020.  
  1021.        GpiMove(hPS,    pcw->aptlXHair);
  1022.        GpiLine(hPS,    &pcw->aptlXHair[1]);
  1023.  
  1024.        GpiMove(hPS,    &pcw->aptlXHair[2]);
  1025.        GpiLine(hPS,    &pcw->aptlXHair[3]);
  1026.  
  1027.                /* Save the new position    of the mouse pointer    */
  1028.                /* within the cross hair    point array        */
  1029.  
  1030.        pcw->aptlXHair[0].y =
  1031.        pcw->aptlXHair[1].y = SHORT2FROMMP(mp1);
  1032.        pcw->aptlXHair[2].x =
  1033.        pcw->aptlXHair[3].x = SHORT1FROMMP(mp1);
  1034.  
  1035.                /* Draw the new cross hair within the invert    */
  1036.                /* mix mode                    */
  1037.  
  1038.        GpiMove(hPS,    pcw->aptlXHair);
  1039.        GpiLine(hPS,    &pcw->aptlXHair[1]);
  1040.  
  1041.        GpiMove(hPS,    &pcw->aptlXHair[2]);
  1042.        GpiLine(hPS,    &pcw->aptlXHair[3]);
  1043.        }
  1044.                /* Release the controls presentation space    */
  1045.        WinReleasePS(hPS);
  1046.        break;
  1047.  
  1048.    /*********************************************************************/
  1049.    /*  Mouse Button 1 release                        */
  1050.    /*********************************************************************/
  1051.  
  1052.    case    WM_BUTTON1UP :
  1053.                /* Get the address of the control info from the    */
  1054.                /* control's reserved memory                     */
  1055.  
  1056.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1057.  
  1058.                /* Determine if the control in capture mode in    */
  1059.                /* case,    the current position of    the mouse    */
  1060.                /* pointer needs    to be checked and the colour    */
  1061.                /* determined                    */
  1062.  
  1063.        if ( pcw->fCapture )
  1064.        {
  1065.                /* Release the mouse capture to allow other    */
  1066.                /* windows the ability of receiving mouse input    */
  1067.  
  1068.        WinSetCapture(HWND_DESKTOP, (HWND)NULL);
  1069.        pcw->fCapture = FALSE;
  1070.  
  1071.                /* Send notification message to control owner    */
  1072.                /* that cross hair has been released        */
  1073.                /*                        */
  1074.                /* Notification:    CWN_XHAIRRELEASED        */
  1075.                /* mp2:        N/A                */
  1076.  
  1077.        WinSendMsg(pcw->hwndOwner, WM_CONTROL,
  1078.               MPFROM2SHORT(pcw->id, CWN_XHAIRRELEASED),    0L);
  1079.  
  1080.                /* Check    to see if notification of RGB or HSB    */
  1081.                /* colour selected required            */
  1082.  
  1083.        if (    pcw->flStyle & (CWS_RGB    | CWS_HSB) )
  1084.            {
  1085.                /* Check    to see if the mouse pointer at the    */
  1086.                /* origin of the    colour wheel in    the horizontal    */
  1087.                /* direction                    */
  1088.  
  1089.            if ( pcw->aptlXHair[2].x    == pcw->ptlOrigin.x )
  1090.  
  1091.                /* Mouse    pointer    aligning horizontally at zero    */
  1092.                /* in the colour    wheel.    Need to    specify    in    */
  1093.                /* radians the angle in which the cross is    */
  1094.                /* resting.  Check to see if the    y position    */
  1095.                /* positive which indicates the angle is    90°    */
  1096.                /* otherwise it is 270°.                */
  1097.  
  1098.            if (    (lRadius = pcw->aptlXHair[0].y - pcw->ptlOrigin.y) < 0 )
  1099.                rdAngle = 4.712388980;
  1100.            else
  1101.                rdAngle = 1.570796327;
  1102.            else
  1103.                /* Check    to see if the mouse pointer at the    */
  1104.                /* origin of the    colour wheel in    the vertical    */
  1105.                /* direction                    */
  1106.  
  1107.            if (    pcw->aptlXHair[0].y == pcw->ptlOrigin.y    )
  1108.  
  1109.                /* Mouse    pointer    aligning horizontally at zero    */
  1110.                /* in the colour    wheel.    Need to    specify    in    */
  1111.                /* radians the angle in which the cross is    */
  1112.                /* resting.  Check to see if the    y position    */
  1113.                /* positive which indicates the angle is    0°    */
  1114.                /* otherwise it is 180°.                */
  1115.  
  1116.                if ( (lRadius = pcw->aptlXHair[2].x - pcw->ptlOrigin.x) < 0 )
  1117.                rdAngle = 3.141592654;
  1118.                else
  1119.                rdAngle = 0.0;
  1120.            else
  1121.                {
  1122.                /* Determine the    absolute x and y co-ordinates    */
  1123.                /* based    upon cartesian system.    All trig    */
  1124.                /* functions are    within the 0 to    90° range.    */
  1125.  
  1126.                if ( pcw->aptlXHair[0].y    < pcw->ptlOrigin.y )
  1127.                y = pcw->ptlOrigin.y    - pcw->aptlXHair[0].y;
  1128.                else
  1129.                y = pcw->aptlXHair[0].y - pcw->ptlOrigin.y;
  1130.  
  1131.                if ( pcw->aptlXHair[2].x    < pcw->ptlOrigin.x )
  1132.                x = pcw->ptlOrigin.x    - pcw->aptlXHair[2].x;
  1133.                else
  1134.                x = pcw->aptlXHair[2].x - pcw->ptlOrigin.x;
  1135.  
  1136.                /* Calculate the    radius from the    x and y        */
  1137.                /* position of the mouse    using trig and right    */
  1138.                /* angle    geometry                */
  1139.  
  1140.                lRadius = (LONG)((double)y / sin(rdAngle    = atan2((double)y, (double)x)));
  1141.  
  1142.                /* Determine the    quadrant that the mouse    pointer    */
  1143.                /* was in to be able to form correct angle    */
  1144.  
  1145.                if ( pcw->aptlXHair[0].y    < pcw->ptlOrigin.y )
  1146.                if (    pcw->aptlXHair[2].x > pcw->ptlOrigin.x )
  1147.                    rdAngle = 6.283185307 - rdAngle;
  1148.                else
  1149.                    rdAngle += 3.141592654;
  1150.                else
  1151.                if (    pcw->aptlXHair[2].x < pcw->ptlOrigin.x )
  1152.                    rdAngle = 3.141592654 - rdAngle;
  1153.                }
  1154.                /* When the style of the    control    requests RGB    */
  1155.                /* notification,    convert    the hue    and saturation    */
  1156.                /* (angle and radius) to    RGB and    create a    */
  1157.                /* notification message package that is sent    */
  1158.                /* back to the owner.                */
  1159.                /*                        */
  1160.                /* Notification:    CWN_RGBCLRSELECTED        */
  1161.                /* mp2:        RGB2 value            */
  1162.  
  1163.            if ( pcw->flStyle & CWS_RGB )
  1164.            WinSendMsg(pcw->hwndOwner, WM_CONTROL,
  1165.                   MPFROM2SHORT(pcw->id, CWN_RGBCLRSELECTED),
  1166.                   MPFROMLONG(lHSBtoRGB((LONG)((rdAngle * 360.0) / 6.283185307),
  1167.                      lRadius * 100 / pcw->lRadius)));
  1168.  
  1169.                /* When the style of the    control    requests HSB    */
  1170.                /* notification,    create a notification message    */
  1171.                /* package that is sent back to the owner.    */
  1172.                /*                        */
  1173.                /* Notification:    CWN_HSBCLRSELECTED        */
  1174.                /* mp2:        Low Short = Hue    (Angle)        */
  1175.                /*        Hi  Short = Saturation (Radius)    */
  1176.  
  1177.            if ( pcw->flStyle & CWS_HSB )
  1178.            WinSendMsg(pcw->hwndOwner, WM_CONTROL,
  1179.                   MPFROM2SHORT(pcw->id, CWN_HSBCLRSELECTED),
  1180.                   MPFROMLONG(MAKELONG((LONG)rdAngle, lRadius * 100 / pcw->lRadius)));
  1181.            }
  1182.        }
  1183.        break;
  1184.  
  1185.    /*********************************************************************/
  1186.    /*  Mouse moving                            */
  1187.    /*********************************************************************/
  1188.  
  1189.    case    WM_MOUSEMOVE :
  1190.                /* Get the address of the control info from the    */
  1191.                /* control's reserved memory                     */
  1192.  
  1193.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1194.  
  1195.                /* Check    to see if in capture mode and if the    */
  1196.                /* case,    need to    move the cross hair that is    */
  1197.                /* used to denote the current colour selected    */
  1198.  
  1199.        if ( pcw->fCapture )
  1200.        {
  1201.                /* Get the current mouse    pointer    position and    */
  1202.                /* place    within the test    point structure        */
  1203.  
  1204.        ptl.x = SHORT1FROMMP(mp1);
  1205.        ptl.y = SHORT2FROMMP(mp1);
  1206.  
  1207.                /* Set up the arc parameters            */
  1208.  
  1209.        pcw->ap.lP =    pcw->ap.lQ = pcw->lRadius;
  1210.        GpiSetArcParams(hPS = WinGetPS(hWnd), &pcw->ap);
  1211.  
  1212.                /* Create the clipping path to encompass    just    */
  1213.                /* the colour wheel itself.  To do this,    open a    */
  1214.                /* normal path and draw a circle    into the path    */
  1215.                /* that has the same radius as the colour wheel.    */
  1216.  
  1217.        GpiBeginPath(hPS, 1L);
  1218.        GpiMove(hPS,    &pcw->ptlOrigin);
  1219.        GpiFullArc(hPS, DRO_OUTLINE,    MAKEFIXED(1, 0));
  1220.        GpiEndPath(hPS);
  1221.  
  1222.                /* Circle complete, convert the normal path to a    */
  1223.                /* clip path to allow the determination of the    */
  1224.                /* mouse    button click within the    colour wheel or    */
  1225.                /* outside the edge of the wheel    but still    */
  1226.                /* within the limits of the control itself    */
  1227.  
  1228.        GpiSetClipPath(hPS, 1L, SCP_ALTERNATE | SCP_AND);
  1229.  
  1230.                /* Check    to see if the mouse pointer button    */
  1231.                /* click    within the confines of the colour    */
  1232.                /* wheel                        */
  1233.  
  1234.        if (    GpiPtVisible(hPS, &ptl)    == PVIS_VISIBLE    )
  1235.            {
  1236.                /* Set the mix mode for line invert        */
  1237.  
  1238.            GpiSetMix(hPS, FM_INVERT);
  1239.  
  1240.                /* Erase    the current cross hair by drawing it    */
  1241.                /* again    which will cause the previous colours    */
  1242.                /* to be    displayed since    it is being drawn in    */
  1243.                /* invert mix mode                */
  1244.  
  1245.            GpiMove(hPS, pcw->aptlXHair);
  1246.            GpiLine(hPS, &pcw->aptlXHair[1]);
  1247.  
  1248.            GpiMove(hPS, &pcw->aptlXHair[2]);
  1249.            GpiLine(hPS, &pcw->aptlXHair[3]);
  1250.  
  1251.                /* Save the new position    of the mouse pointer    */
  1252.                /* within the cross hair    point array        */
  1253.  
  1254.            pcw->aptlXHair[0].y =
  1255.            pcw->aptlXHair[1].y = SHORT2FROMMP(mp1);
  1256.            pcw->aptlXHair[2].x =
  1257.            pcw->aptlXHair[3].x = SHORT1FROMMP(mp1);
  1258.  
  1259.                /* Draw the new cross hair within the invert    */
  1260.                /* mix mode                    */
  1261.  
  1262.            GpiMove(hPS, pcw->aptlXHair);
  1263.            GpiLine(hPS, &pcw->aptlXHair[1]);
  1264.  
  1265.            GpiMove(hPS, &pcw->aptlXHair[2]);
  1266.            GpiLine(hPS, &pcw->aptlXHair[3]);
  1267.            }
  1268.                /* Release the controls presentation space    */
  1269.  
  1270.        WinReleasePS(hPS);
  1271.        }
  1272.                /* Set the mouse    pointer    to the arrow shape    */
  1273.                /* while    the mouse within the control        */
  1274.  
  1275.        WinSetPointer(HWND_DESKTOP, pcw->hptrArrow);
  1276.        break;
  1277.  
  1278. /************************************************************************/
  1279. /************************************************************************/
  1280. /*                                    */
  1281. /* Part    4: Painting and    display                        */
  1282. /*                                    */
  1283. /************************************************************************/
  1284. /************************************************************************/
  1285.  
  1286.    /*********************************************************************/
  1287.    /*  Erase control background                        */
  1288.    /*********************************************************************/
  1289.  
  1290.    case    WM_ERASEBACKGROUND :
  1291.        WinQueryWindowRect(hWnd,    &rcl);
  1292.        WinFillRect((HPS)mp1, &rcl, SYSCLR_FIELDBACKGROUND);
  1293.        break;
  1294.  
  1295.    /*********************************************************************/
  1296.    /*  Paint control                            */
  1297.    /*********************************************************************/
  1298.  
  1299.    case    WM_PAINT :
  1300.                /* Get the address of the control info from the    */
  1301.                /* control's reserved memory                     */
  1302.  
  1303.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1304.  
  1305.        hPS = WinBeginPaint(hWnd, (HPS)NULL, (PRECTL)NULL);
  1306.  
  1307.                /* Check    to see if the control is threaded and    */
  1308.                /* has a    bitmap display                */
  1309.  
  1310.        if ( (pcw->flStyle & (CWS_BITMAP    | CWS_THREADED)) == (CWS_BITMAP    | CWS_THREADED)    )
  1311.  
  1312.                /* Threaded version of the control being    used,    */
  1313.                /* check    to make    sure that the thread is    active    */
  1314.                /* which    indicates that the bitmap is still    */
  1315.                /* being    constructed and    that the outline of the    */
  1316.                /* should only be shown.     This acts like    a    */
  1317.                /* prevent semaphore except that    no blocking on    */
  1318.                /* the semaphore    occurs as this would block the    */
  1319.                /* rest of the users PM interface.        */
  1320.        if (    pcw->tid )
  1321.            {
  1322.                /* Set up the arc parameters            */
  1323.  
  1324.            pcw->ap.lP = pcw->ap.lQ = pcw->lRadius;
  1325.            GpiSetArcParams(hPS, &pcw->ap);
  1326.  
  1327.                /* Create the clipping path to encompass    just    */
  1328.                /* the colour wheel itself.  To do this,    open a    */
  1329.                /* normal path and draw a circle    into the path    */
  1330.                /* that has the same radius as the colour wheel.    */
  1331.  
  1332.            GpiMove(hPS, &pcw->ptlOrigin);
  1333.            GpiFullArc(hPS, DRO_OUTLINE, MAKEFIXED(1, 0));
  1334.            WinEndPaint(hPS);
  1335.            break;
  1336.            }
  1337.                /* Check    to see if the bitmap is    ready.    This    */
  1338.                /* will be indicated by the handle being        */
  1339.                /* present somewhat like    the prescence of the    */
  1340.                /* thread ID when the bitmap is being drawn.    */
  1341.        if ( pcw->hbm )
  1342.        GpiWCBitBlt(hPS, pcw->hbm, 4L, pcw->aptl, ROP_SRCCOPY, BBO_OR);
  1343.        else
  1344.                /* Get the address of the control info from the    */
  1345.                /* control's reserved memory                     */
  1346.  
  1347.        DrawClrWheel(hPS, pcw);
  1348.  
  1349.                /* Set up the arc parameters for    the clipping    */
  1350.                /* path                        */
  1351.  
  1352.        pcw->ap.lP = pcw->ap.lQ = pcw->lRadius;
  1353.        GpiSetArcParams(hPS, &pcw->ap);
  1354.  
  1355.                /* Create the clipping path to encompass    just    */
  1356.                /* the colour wheel itself.  To do this,    open a    */
  1357.                /* normal path and draw a circle    into the path    */
  1358.                /* that has the same radius as the colour wheel.    */
  1359.  
  1360.        GpiBeginPath(hPS, 1L);
  1361.        GpiMove(hPS, &pcw->ptlOrigin);
  1362.        GpiFullArc(hPS, DRO_OUTLINE, MAKEFIXED(1, 0));
  1363.        GpiEndPath(hPS);
  1364.                /* Circle complete, convert the normal path to a    */
  1365.                /* clip path to allow the determination of the    */
  1366.                /* mouse    button click within the    colour wheel or    */
  1367.                /* outside the edge of the wheel    but still    */
  1368.                /* within the limits of the control itself    */
  1369.  
  1370.        GpiSetClipPath(hPS, 1L, SCP_ALTERNATE | SCP_AND);
  1371.  
  1372.                /* Set the mix mode for line invert        */
  1373.  
  1374.        GpiSetMix(hPS, FM_INVERT);
  1375.  
  1376.                /* Draw the new cross hair within the invert    */
  1377.                /* mix mode                    */
  1378.  
  1379.        GpiMove(hPS, pcw->aptlXHair);
  1380.        GpiLine(hPS, &pcw->aptlXHair[1]);
  1381.  
  1382.        GpiMove(hPS, &pcw->aptlXHair[2]);
  1383.        GpiLine(hPS, &pcw->aptlXHair[3]);
  1384.        WinEndPaint(hPS);
  1385.        break;
  1386.  
  1387. /************************************************************************/
  1388. /************************************************************************/
  1389. /*                                    */
  1390. /* Part    5: Control defined message handling                */
  1391. /*                                    */
  1392. /************************************************************************/
  1393. /************************************************************************/
  1394.  
  1395.    /*********************************************************************/
  1396.    /*  Cross-hair position query                    */
  1397.    /*********************************************************************/
  1398.    /*********************************************************************/
  1399.    /*                                    */
  1400.    /*  Message:                                */
  1401.    /*           CWM_QUERYXHAIR                        */
  1402.    /*                                    */
  1403.    /*  Input:                                */
  1404.    /*           mp1 = 0L;                        */
  1405.    /*           mp2 = 0L;                        */
  1406.    /*                                    */
  1407.    /*  Return:                                */
  1408.    /*           x = SHORT1FROMMR(mr);                    */
  1409.    /*           y = SHORT2FROMMR(mr);                    */
  1410.    /*                                    */
  1411.    /*********************************************************************/
  1412.  
  1413.    case    CWM_QUERYXHAIR :
  1414.                /* Get the address of the control info from the    */
  1415.                /* control's reserved memory                     */
  1416.  
  1417.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1418.  
  1419.                /* Return the cross position with the x in the    */
  1420.                /* lower    portion    and the    y in the upper portion    */
  1421.                /* of the return    value                */
  1422.  
  1423.        return(MRFROMLONG(MAKELONG((USHORT)pcw->aptlXHair[2].x, (USHORT)pcw->aptlXHair[0].y)));
  1424.  
  1425.    /*********************************************************************/
  1426.    /*  Cross-hair position set                        */
  1427.    /*********************************************************************/
  1428.    /*********************************************************************/
  1429.    /*                                    */
  1430.    /*  Message:                                */
  1431.    /*           CWM_SETXHAIR                        */
  1432.    /*                                    */
  1433.    /*  Input:                                */
  1434.    /*           mp1 = x;                            */
  1435.    /*           mp2 = y;                            */
  1436.    /*                                    */
  1437.    /*  Return:                                */
  1438.    /*           TRUE  : position    accepted and cross hair    updated        */
  1439.    /*           FALSE : invalid position    specified, cross hair not    */
  1440.    /*               updated                        */
  1441.    /*                                    */
  1442.    /*********************************************************************/
  1443.  
  1444.    case    CWM_SETXHAIR :
  1445.                /* Get the address of the control info from the    */
  1446.                /* control's reserved memory                     */
  1447.  
  1448.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1449.  
  1450.                /* Get the position and place within the    test    */
  1451.                /* point    structure                */
  1452.  
  1453.        ptl.x = LONGFROMMP(mp1);
  1454.        ptl.y = LONGFROMMP(mp2);
  1455.  
  1456.                /* Set up the arc parameters            */
  1457.  
  1458.        pcw->ap.lP = pcw->ap.lQ = pcw->lRadius;
  1459.        GpiSetArcParams(hPS = WinGetPS(hWnd), &pcw->ap);
  1460.  
  1461.                /* Create the clipping path to encompass    just    */
  1462.                /* the colour wheel itself.  To do this,    open a    */
  1463.                /* normal path and draw a circle    into the path    */
  1464.                /* that has the same radius as the colour wheel.    */
  1465.  
  1466.        GpiBeginPath(hPS, 1L);
  1467.        GpiMove(hPS, &pcw->ptlOrigin);
  1468.        GpiFullArc(hPS, DRO_OUTLINE, MAKEFIXED(1, 0));
  1469.        GpiEndPath(hPS);
  1470.                /* Circle complete, convert the normal path to a    */
  1471.                /* clip path to allow the determination of the    */
  1472.                /* mouse    button click within the    colour wheel or    */
  1473.                /* outside the edge of the wheel    but still    */
  1474.                /* within the limits of the control itself    */
  1475.  
  1476.        GpiSetClipPath(hPS, 1L, SCP_ALTERNATE | SCP_AND);
  1477.  
  1478.                /* Check    to see if the mouse pointer button    */
  1479.                /* click    within the confines of the colour    */
  1480.                /* wheel                        */
  1481.  
  1482.        if ( GpiPtVisible(hPS, &ptl) == PVIS_VISIBLE )
  1483.        {
  1484.                /* Set the mix mode for line invert        */
  1485.  
  1486.        GpiSetMix(hPS, FM_INVERT);
  1487.  
  1488.                /* Erase    the current cross hair by drawing it    */
  1489.                /* again    which will cause the previous colours    */
  1490.                /* to be    displayed since    it is being drawn in    */
  1491.                /* invert mix mode                */
  1492.  
  1493.        GpiMove(hPS,    pcw->aptlXHair);
  1494.        GpiLine(hPS,    &pcw->aptlXHair[1]);
  1495.  
  1496.        GpiMove(hPS,    &pcw->aptlXHair[2]);
  1497.        GpiLine(hPS,    &pcw->aptlXHair[3]);
  1498.  
  1499.                /* Save the new position    of the mouse pointer    */
  1500.                /* within the cross hair    point array        */
  1501.  
  1502.        pcw->aptlXHair[0].y =
  1503.        pcw->aptlXHair[1].y = LONGFROMMP(mp2);
  1504.        pcw->aptlXHair[2].x =
  1505.        pcw->aptlXHair[3].x = LONGFROMMP(mp1);
  1506.  
  1507.                /* Draw the new cross hair within the invert    */
  1508.                /* mix mode                    */
  1509.  
  1510.        GpiMove(hPS,    pcw->aptlXHair);
  1511.        GpiLine(hPS,    &pcw->aptlXHair[1]);
  1512.  
  1513.        GpiMove(hPS,    &pcw->aptlXHair[2]);
  1514.        GpiLine(hPS,    &pcw->aptlXHair[3]);
  1515.        fReturn = TRUE;
  1516.        }
  1517.        else
  1518.        fReturn = FALSE;
  1519.  
  1520.                /* Release the controls presentation space    */
  1521.        WinReleasePS(hPS);
  1522.        return(MRFROMLONG(fReturn));
  1523.  
  1524.    /*********************************************************************/
  1525.    /*  RGB colour query                            */
  1526.    /*********************************************************************/
  1527.    /*********************************************************************/
  1528.    /*                                    */
  1529.    /*  Message:                                */
  1530.    /*           CWM_QUERYRGBCLR                        */
  1531.    /*                                    */
  1532.    /*  Input:                                */
  1533.    /*           mp1 = 0L;                        */
  1534.    /*           mp2 = 0L;                        */
  1535.    /*                                    */
  1536.    /*  Return:                                */
  1537.    /*           RGB2 rgb2 = LONGFROMMR(mr);                */
  1538.    /*                                    */
  1539.    /*********************************************************************/
  1540.  
  1541.    case    CWM_QUERYRGBCLR    :
  1542.                /* Get the address of the control info from the    */
  1543.                /* control's reserved memory                     */
  1544.  
  1545.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1546.  
  1547.                /* Check    to see if the mouse pointer at the    */
  1548.                /* origin of the    colour wheel in    the horizontal    */
  1549.                /* direction                    */
  1550.  
  1551.        if ( pcw->aptlXHair[2].x    == pcw->ptlOrigin.x )
  1552.  
  1553.                /* Mouse    pointer    aligning horizontally at zero    */
  1554.                /* in the colour    wheel.    Need to    specify    in    */
  1555.                /* radians the angle in which the cross is    */
  1556.                /* resting.  Check to see if the    y position    */
  1557.                /* positive which indicates the angle is    90°    */
  1558.                /* otherwise it is 270°.                */
  1559.  
  1560.            if ( (lRadius = pcw->aptlXHair[0].y - pcw->ptlOrigin.y) < 0 )
  1561.            rdAngle = 4.712388980;
  1562.            else
  1563.            rdAngle = 1.570796327;
  1564.        else
  1565.                /* Check    to see if the mouse pointer at the    */
  1566.                /* origin of the    colour wheel in    the vertical    */
  1567.                /* direction                    */
  1568.  
  1569.            if ( pcw->aptlXHair[0].y    == pcw->ptlOrigin.y )
  1570.  
  1571.                /* Mouse    pointer    aligning horizontally at zero    */
  1572.                /* in the colour    wheel.    Need to    specify    in    */
  1573.                /* radians the angle in which the cross is    */
  1574.                /* resting.  Check to see if the    y position    */
  1575.                /* positive which indicates the angle is    0°    */
  1576.                /* otherwise it is 180°.                */
  1577.  
  1578.            if (    (lRadius = pcw->aptlXHair[2].x - pcw->ptlOrigin.x) < 0 )
  1579.                rdAngle = 3.141592654;
  1580.            else
  1581.                rdAngle = 0.0;
  1582.            else
  1583.            {
  1584.                /* Determine the    absolute x and y co-ordinates    */
  1585.                /* based    upon cartesian system.    All trig    */
  1586.                /* functions are    within the 0 to    90° range.    */
  1587.  
  1588.            if (    pcw->aptlXHair[0].y < pcw->ptlOrigin.y )
  1589.                y = pcw->ptlOrigin.y - pcw->aptlXHair[0].y;
  1590.            else
  1591.                y = pcw->aptlXHair[0].y - pcw->ptlOrigin.y;
  1592.  
  1593.            if (    pcw->aptlXHair[2].x < pcw->ptlOrigin.x )
  1594.                x = pcw->ptlOrigin.x - pcw->aptlXHair[2].x;
  1595.            else
  1596.                x = pcw->aptlXHair[2].x - pcw->ptlOrigin.x;
  1597.  
  1598.                /* Calculate the    radius from the    x and y        */
  1599.                /* position of the mouse    using trig and right    */
  1600.                /* angle    geometry                */
  1601.  
  1602.            lRadius = (LONG)((double)y /    sin(rdAngle = atan2((double)y, (double)x)));
  1603.  
  1604.                /* Determine the    quadrant that the mouse    pointer    */
  1605.                /* was in to be able to form correct angle    */
  1606.  
  1607.            if (    pcw->aptlXHair[0].y < pcw->ptlOrigin.y )
  1608.                if ( pcw->aptlXHair[2].x    > pcw->ptlOrigin.x )
  1609.                rdAngle = 6.283185307 - rdAngle;
  1610.                else
  1611.                rdAngle += 3.141592654;
  1612.            else
  1613.                if ( pcw->aptlXHair[2].x    < pcw->ptlOrigin.x )
  1614.                rdAngle = 3.141592654 - rdAngle;
  1615.            }
  1616.        return(MRFROMLONG(lHSBtoRGB((LONG)((rdAngle * 360.0) / 6.283185307),
  1617.           lRadius *    100 / pcw->lRadius)));
  1618.  
  1619.    /*********************************************************************/
  1620.    /*  RGB colour set                            */
  1621.    /*********************************************************************/
  1622.    /*********************************************************************/
  1623.    /*                                    */
  1624.    /*  Message:                                */
  1625.    /*           CWM_SETRGBCLR                        */
  1626.    /*                                    */
  1627.    /*  Input:                                */
  1628.    /*           mp1 = RGB2 rgb2;                        */
  1629.    /*           mp2 = 0L;                        */
  1630.    /*                                    */
  1631.    /*  Return:                                */
  1632.    /*           x = SHORT1FROMMR(mr);                    */
  1633.    /*           y = SHORT2FROMMR(mr);                    */
  1634.    /*                                    */
  1635.    /*********************************************************************/
  1636.  
  1637.    case    CWM_SETRGBCLR :
  1638.                /* Get the address of the control info from the    */
  1639.                /* control's reserved memory                     */
  1640.  
  1641.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1642.  
  1643.                /* Get the RGB from the message parameter    */
  1644.  
  1645.        prgb2 = (PRGB2)mp1;
  1646.  
  1647.        lMin = min(prgb2->bRed, min(prgb2->bGreen, prgb2->bBlue));
  1648.  
  1649.        if ( lMax = max(prgb2->bRed, max(prgb2->bGreen, prgb2->bBlue)) )
  1650.        {
  1651.        lRadius = ((lMax - lMin) * pcw->lRadius) / lMax;
  1652.  
  1653.        if (    lMax ==    lMin )
  1654.            lAngle =    0L;
  1655.        else
  1656.            if ( prgb2->bRed    == lMax    )
  1657.            lAngle = ((prgb2->bGreen - prgb2->bBlue) * 60L) / (lMax - lMin);
  1658.            else
  1659.            if (    prgb2->bGreen == lMax )
  1660.                lAngle =    120 + ((prgb2->bBlue - prgb2->bRed) * 60L) / (lMax - lMin);
  1661.            else
  1662.                if ( prgb2->bBlue == lMax )
  1663.                lAngle = 240    + ((prgb2->bRed    - prgb2->bGreen) * 60L)    / (lMax    - lMin);
  1664.  
  1665.        if (    lAngle < 0L )
  1666.            lAngle += 360;
  1667.        }
  1668.        else
  1669.        lRadius = lAngle = 0L;
  1670.  
  1671.                /* Set up the arc parameters            */
  1672.  
  1673.        pcw->ap.lP = pcw->ap.lQ = pcw->lRadius;
  1674.        GpiSetArcParams(hPS = WinGetPS(hWnd), &pcw->ap);
  1675.  
  1676.                /* Create the clipping path to encompass    just    */
  1677.                /* the colour wheel itself.  To do this,    open a    */
  1678.                /* normal path and draw a circle    into the path    */
  1679.                /* that has the same radius as the colour wheel.    */
  1680.  
  1681.        GpiBeginPath(hPS, 1L);
  1682.        GpiMove(hPS, &pcw->ptlOrigin);
  1683.        GpiFullArc(hPS, DRO_OUTLINE, MAKEFIXED(1, 0));
  1684.        GpiEndPath(hPS);
  1685.                /* Circle complete, convert the normal path to a    */
  1686.                /* clip path to allow the determination of the    */
  1687.                /* mouse    button click within the    colour wheel or    */
  1688.                /* outside the edge of the wheel    but still    */
  1689.                /* within the limits of the control itself    */
  1690.  
  1691.        GpiSetClipPath(hPS, 1L, SCP_ALTERNATE | SCP_AND);
  1692.  
  1693.                /* Set the mix mode for line invert        */
  1694.  
  1695.        GpiSetMix(hPS, FM_INVERT);
  1696.  
  1697.                /* Erase    the current cross hair by drawing it    */
  1698.                /* again    which will cause the previous colours    */
  1699.                /* to be    displayed since    it is being drawn in    */
  1700.                /* invert mix mode                */
  1701.  
  1702.        GpiMove(hPS, pcw->aptlXHair);
  1703.        GpiLine(hPS, &pcw->aptlXHair[1]);
  1704.  
  1705.        GpiMove(hPS, &pcw->aptlXHair[2]);
  1706.        GpiLine(hPS, &pcw->aptlXHair[3]);
  1707.  
  1708.                /* Save the new position    of the mouse pointer    */
  1709.                /* within the cross hair    point array        */
  1710.  
  1711.        pcw->aptlXHair[2].x =
  1712.        pcw->aptlXHair[3].x = (LONG)((double)lRadius * cos(rdAngle = (double)lAngle / 57.29577951)) +
  1713.                  pcw->ptlOrigin.x;
  1714.        pcw->aptlXHair[0].y =
  1715.        pcw->aptlXHair[1].y = (LONG)((double)lRadius * sin(rdAngle)) + pcw->ptlOrigin.y;
  1716.  
  1717.                /* Draw the new cross hair within the invert    */
  1718.                /* mix mode                    */
  1719.  
  1720.        GpiMove(hPS, pcw->aptlXHair);
  1721.        GpiLine(hPS, &pcw->aptlXHair[1]);
  1722.  
  1723.        GpiMove(hPS, &pcw->aptlXHair[2]);
  1724.        GpiLine(hPS, &pcw->aptlXHair[3]);
  1725.  
  1726.                /* Release the controls presentation space    */
  1727.  
  1728.        WinReleasePS(hPS);
  1729.        return(MRFROMLONG(MAKELONG((USHORT)pcw->aptlXHair[2].x, (USHORT)pcw->aptlXHair[0].y)));
  1730.  
  1731.    /*********************************************************************/
  1732.    /*  HSB colour query                            */
  1733.    /*********************************************************************/
  1734.    /*********************************************************************/
  1735.    /*                                    */
  1736.    /*  Message:                                */
  1737.    /*           CWM_QUERYHSBCLR                        */
  1738.    /*                                    */
  1739.    /*  Input:                                */
  1740.    /*           mp1 = 0L;                        */
  1741.    /*           mp2 = 0L;                        */
  1742.    /*                                    */
  1743.    /*  Return:                                */
  1744.    /*           sHue       = SHORT1FROMMR(mr);                */
  1745.    /*           sSaturation = SHORT2FROMMR(mr);                */
  1746.    /*                                    */
  1747.    /*********************************************************************/
  1748.  
  1749.    case    CWM_QUERYHSBCLR    :
  1750.                /* Get the address of the control info from the    */
  1751.                /* control's reserved memory                     */
  1752.  
  1753.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1754.  
  1755.                /* Check    to see if the mouse pointer at the    */
  1756.                /* origin of the    colour wheel in    the horizontal    */
  1757.                /* direction                    */
  1758.  
  1759.        if ( pcw->aptlXHair[2].x    == pcw->ptlOrigin.x )
  1760.  
  1761.                /* Mouse    pointer    aligning horizontally at zero    */
  1762.                /* in the colour    wheel.    Need to    specify    in    */
  1763.                /* radians the angle in which the cross is    */
  1764.                /* resting.  Check to see if the    y position    */
  1765.                /* positive which indicates the angle is    90°    */
  1766.                /* otherwise it is 270°.                */
  1767.  
  1768.            if ( (lRadius = pcw->aptlXHair[0].y - pcw->ptlOrigin.y) < 0 )
  1769.            rdAngle = 4.712388980;
  1770.            else
  1771.            rdAngle = 1.570796327;
  1772.        else
  1773.                /* Check    to see if the mouse pointer at the    */
  1774.                /* origin of the    colour wheel in    the vertical    */
  1775.                /* direction                    */
  1776.  
  1777.            if ( pcw->aptlXHair[0].y    == pcw->ptlOrigin.y )
  1778.  
  1779.                /* Mouse    pointer    aligning horizontally at zero    */
  1780.                /* in the colour    wheel.    Need to    specify    in    */
  1781.                /* radians the angle in which the cross is    */
  1782.                /* resting.  Check to see if the    y position    */
  1783.                /* positive which indicates the angle is    0°    */
  1784.                /* otherwise it is 180°.                */
  1785.  
  1786.            if (    (lRadius = pcw->aptlXHair[2].x - pcw->ptlOrigin.x) < 0 )
  1787.                rdAngle = 3.141592654;
  1788.            else
  1789.                rdAngle = 0.0;
  1790.            else
  1791.            {
  1792.                /* Determine the    absolute x and y co-ordinates    */
  1793.                /* based    upon cartesian system.    All trig    */
  1794.                /* functions are    within the 0 to    90° range.    */
  1795.  
  1796.            if (    pcw->aptlXHair[0].y < pcw->ptlOrigin.y )
  1797.                y = pcw->ptlOrigin.y - pcw->aptlXHair[0].y;
  1798.            else
  1799.                y = pcw->aptlXHair[0].y - pcw->ptlOrigin.y;
  1800.  
  1801.            if (    pcw->aptlXHair[2].x < pcw->ptlOrigin.x )
  1802.                x = pcw->ptlOrigin.x - pcw->aptlXHair[2].x;
  1803.            else
  1804.                x = pcw->aptlXHair[2].x - pcw->ptlOrigin.x;
  1805.  
  1806.                /* Calculate the    radius from the    x and y        */
  1807.                /* position of the mouse    using trig and right    */
  1808.                /* angle    geometry                */
  1809.  
  1810.            lRadius = (LONG)((double)y /    sin(rdAngle = atan2((double)y, (double)x)));
  1811.  
  1812.                /* Determine the    quadrant that the mouse    pointer    */
  1813.                /* was in to be able to form correct angle    */
  1814.  
  1815.            if (    pcw->aptlXHair[0].y < pcw->ptlOrigin.y )
  1816.                if ( pcw->aptlXHair[2].x    > pcw->ptlOrigin.x )
  1817.                rdAngle = 6.283185307 - rdAngle;
  1818.                else
  1819.                rdAngle += 3.141592654;
  1820.            else
  1821.                if ( pcw->aptlXHair[2].x    < pcw->ptlOrigin.x )
  1822.                rdAngle = 3.141592654 - rdAngle;
  1823.            }
  1824.        return(MRFROMLONG(MAKELONG((LONG)rdAngle, lRadius * 100 / pcw->lRadius)));
  1825.  
  1826.    /*********************************************************************/
  1827.    /*  Set HSB colour                            */
  1828.    /*********************************************************************/
  1829.    /*********************************************************************/
  1830.    /*                                    */
  1831.    /*  Message:                                */
  1832.    /*           CWM_SETHSBCLR                        */
  1833.    /*                                    */
  1834.    /*  Input:                                */
  1835.    /*           mp1 = lHue;                        */
  1836.    /*           mp2 = lSaturation;                    */
  1837.    /*                                    */
  1838.    /*  Return:                                */
  1839.    /*           x = SHORT1FROMMR(mr);                    */
  1840.    /*           y = SHORT2FROMMR(mr);                    */
  1841.    /*                                    */
  1842.    /*********************************************************************/
  1843.  
  1844.    case    CWM_SETHSBCLR :
  1845.                /* Get the address of the control info from the    */
  1846.                /* control's reserved memory                     */
  1847.  
  1848.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1849.  
  1850.                /* Get the hue (angle) and the saturation    */
  1851.                /* (radius)                    */
  1852.  
  1853.        lAngle  = LONGFROMMP(mp1);
  1854.        lRadius = LONGFROMMP(mp2);
  1855.  
  1856.                /* Set up the arc parameters            */
  1857.  
  1858.        pcw->ap.lP = pcw->ap.lQ = pcw->lRadius;
  1859.        GpiSetArcParams(hPS = WinGetPS(hWnd), &pcw->ap);
  1860.  
  1861.                /* Create the clipping path to encompass    just    */
  1862.                /* the colour wheel itself.  To do this,    open a    */
  1863.                /* normal path and draw a circle    into the path    */
  1864.                /* that has the same radius as the colour wheel.    */
  1865.  
  1866.        GpiBeginPath(hPS, 1L);
  1867.        GpiMove(hPS, &pcw->ptlOrigin);
  1868.        GpiFullArc(hPS, DRO_OUTLINE, MAKEFIXED(1, 0));
  1869.        GpiEndPath(hPS);
  1870.                /* Circle complete, convert the normal path to a    */
  1871.                /* clip path to allow the determination of the    */
  1872.                /* mouse    button click within the    colour wheel or    */
  1873.                /* outside the edge of the wheel    but still    */
  1874.                /* within the limits of the control itself    */
  1875.  
  1876.        GpiSetClipPath(hPS, 1L, SCP_ALTERNATE | SCP_AND);
  1877.  
  1878.                /* Set the mix mode for line invert        */
  1879.  
  1880.        GpiSetMix(hPS, FM_INVERT);
  1881.  
  1882.                /* Erase    the current cross hair by drawing it    */
  1883.                /* again    which will cause the previous colours    */
  1884.                /* to be    displayed since    it is being drawn in    */
  1885.                /* invert mix mode                */
  1886.  
  1887.        GpiMove(hPS, pcw->aptlXHair);
  1888.        GpiLine(hPS, &pcw->aptlXHair[1]);
  1889.  
  1890.        GpiMove(hPS, &pcw->aptlXHair[2]);
  1891.        GpiLine(hPS, &pcw->aptlXHair[3]);
  1892.  
  1893.                /* Save the new position    of the mouse pointer    */
  1894.                /* within the cross hair    point array        */
  1895.  
  1896.        pcw->aptlXHair[2].x =
  1897.        pcw->aptlXHair[3].x = (LONG)((double)lRadius * cos(rdAngle = (double)lAngle / 57.29577951)) +
  1898.                  pcw->ptlOrigin.x;
  1899.        pcw->aptlXHair[0].y =
  1900.        pcw->aptlXHair[1].y = (LONG)((double)lRadius * sin(rdAngle)) + pcw->ptlOrigin.y;
  1901.  
  1902.                /* Draw the new cross hair within the invert    */
  1903.                /* mix mode                    */
  1904.  
  1905.        GpiMove(hPS, pcw->aptlXHair);
  1906.        GpiLine(hPS, &pcw->aptlXHair[1]);
  1907.  
  1908.        GpiMove(hPS, &pcw->aptlXHair[2]);
  1909.        GpiLine(hPS, &pcw->aptlXHair[3]);
  1910.  
  1911.                /* Release the controls presentation space    */
  1912.  
  1913.        WinReleasePS(hPS);
  1914.        return(MRFROMLONG(MAKELONG((USHORT)pcw->aptlXHair[2].x, (USHORT)pcw->aptlXHair[0].y)));
  1915.  
  1916. /************************************************************************/
  1917. /************************************************************************/
  1918. /*                                    */
  1919. /* Part    6: Control destruction coding                    */
  1920. /*                                    */
  1921. /************************************************************************/
  1922. /************************************************************************/
  1923.  
  1924.    /*********************************************************************/
  1925.    /*  Control being destroyed,    perform    clean-up            */
  1926.    /*********************************************************************/
  1927.  
  1928.    case    WM_DESTROY :
  1929.                /* Get the address of the control info from the    */
  1930.                /* control's reserved memory                     */
  1931.  
  1932.        pcw = (PCLRWHEEL)WinQueryWindowPtr(hWnd,    QUCWP_WNDP);
  1933.        if ( pcw->tid )
  1934.        {
  1935.        if (    pcw->hpsBitmap )
  1936.            GpiSetStopDraw(pcw->hpsBitmap, SDW_ON);
  1937.        DosKillThread(pcw->tid);
  1938.        }
  1939.        WinDestroyPointer(pcw->hptrArrow);
  1940.        if ( pcw->hbm )
  1941.        GpiDeleteBitmap(pcw->hbm);
  1942.        DosFreeMem((PVOID)pcw);
  1943.        break;
  1944.                /* Default message processing            */
  1945.    default:
  1946.        return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  1947.    }
  1948. return(0L);
  1949. }
  1950.