home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ctrl2.zip / BARCHART.C next >
C/C++ Source or Header  |  1996-06-02  |  89KB  |  1,790 lines

  1. #pragma title("Bar Chart Control  --  Version 1.0 -- (BarChart.C)")
  2. #pragma subtitle("  Bar Chart Control DLL - Interface Definitions")
  3.  
  4. #pragma info(noext)
  5.  
  6. #define INCL_DOS                   /* Include OS/2 DOS Kernal           */
  7. #define INCL_GPI                   /* Include OS/2 PM GPI Interface     */
  8. #define INCL_WIN                   /* Include OS/2 PM Windows Interface */
  9.  
  10. static char *MODID = "@(#)barchart.c:1.00";
  11.  
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <os2.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18.  
  19. #define MAXTICK 100
  20.  
  21. #include <pmcx.h>
  22.  
  23. #include "barchart.h"
  24.  
  25. /* This module contains an example installable control that can be used */
  26. /* within applications where additional facilities are provided that    */
  27. /* are not found within the default controls of OS/2 PM.                */
  28. /*                                                                      */
  29. /* For complete details regarding the PM Control Extensions (PMCX)      */
  30. /* consult the User's Guide.                                            */
  31. /*                                                                      */
  32. /* The DLL is created using the following command line invocation:      */
  33. /*                                                                      */
  34. /*     Icc -G5e- -O+ -Rn -C BarChart.C                                  */
  35.  
  36. /* Filename:   BarChart.C                                               */
  37.  
  38. /*  Version:   1.0                                                      */
  39. /*  Created:   1996-02-20                                               */
  40. /*  Revised:   1996-02-22                                               */
  41.  
  42. /* Routines:   BOOL EXPENTRY BarChartRegister(HAB hAB);                 */
  43. /*             BOOL EXPENTRY BarChartQuery(PUSERINFO pControlInfo);     */
  44. /*             MRESULT EXPENTRY BarChartWndProc(HWND hWnd, ULONG msg,   */
  45. /*                                              MPARAM mp1, MPARAM mp2);*/
  46. /*             MRESULT EXPENTRY BarChartStyles(HWND hWnd, ULONG msg,    */
  47. /*                                             MPARAM mp1, MPARAM mp2); */
  48.  
  49.  
  50. /* Copyright ╕ 1989-1996  Prominare Inc.  All Rights Reserved.          */
  51.  
  52. /* -------------------------------------------------------------------- */
  53.  
  54. /************************************************************************/
  55. /************************************************************************/
  56. /*                     DISCLAIMER OF WARRANTIES.                        */
  57. /************************************************************************/
  58. /************************************************************************/
  59. /*     The following [enclosed] code is library code created by         */
  60. /*     Prominare Inc.  This library code is  provided to you solely     */
  61. /*     for the purpose of assisting you in the development of your      */
  62. /*     applications.  The code is provided "AS IS", without             */
  63. /*     warranty of any kind.  Prominare Inc. shall not be liable        */
  64. /*     for any damages arising out of your use of the library code,     */
  65. /*     even if they have been advised of the possibility of such        */
  66. /*     damages.                                                         */
  67. /************************************************************************/
  68. /************************************************************************/
  69.  
  70. /* --- Module Data Definitions ---------------------------------------- */
  71.  
  72. static GRADIENTL gradl = { 0L, 1L };
  73.  
  74. #define RGB_DARKGRAY   0x00838383L
  75. #define RGB_PALEGRAY   0x00ccccccL
  76.  
  77. /* --- Module Prototype Definitions ----------------------------------- */
  78.  
  79. static VOID CalcSize(HWND hWnd, PRECTL prcl, PBARCHART pbc);
  80. BOOL    EXPENTRY BarChartRegister(HAB hAB);
  81. BOOL    EXPENTRY BarChartQuery(PUSERINFO pUserInfo);
  82. MRESULT EXPENTRY BarChartWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  83. MRESULT EXPENTRY BarChartStyles(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  84.  
  85. #pragma subtitle("   Bar Chart Control DLL - Control Initialization Function")
  86. #pragma page ( )
  87.  
  88. /* --- BarChartRegister -------------------------------- [ Public ] --- */
  89. /*                                                                      */
  90. /*     This function is used to register the installable control class  */
  91. /*     with OS/2 Presentation Manager.  The registration must use the   */
  92. /*     USER_CWINDOWWORDS to reserve memory for the control to allow for */
  93. /*     proper usage by Resource Editor and for use by the control       */
  94. /*     dialog and window procedures.  The information for the control   */
  95. /*     containing the style, presentation parameters and control data   */
  96. /*     is pointed to by a pointer that can be referenced by the         */
  97. /*     control's dialog and window procedure as required.  The memory   */
  98. /*     for the structure is allocated and controlled through Resource   */
  99. /*     Editor.   The control can reserve more memory for its use        */
  100. /*     by adding the memory required to that of the USER_CWINDOWWORDS   */
  101. /*     constant.                                                        */
  102. /*                                                                      */
  103. /*     Upon Entry:                                                      */
  104. /*                                                                      */
  105. /*     HAB hAB; = Application Anchor Block Handle                       */
  106. /*                                                                      */
  107. /*     Upon Exit:                                                       */
  108. /*                                                                      */
  109. /*     BarChartRegister =  TRUE : Class Registration Successful         */
  110. /*                      = FALSE : Class Registration Failed             */
  111. /*                                                                      */
  112. /* -------------------------------------------------------------------- */
  113.  
  114. BOOL EXPENTRY BarChartRegister(HAB hAB)
  115.  
  116. {
  117.                        /* Register the control class with OS/2          */
  118.                        /* Presentation Manager and return registration  */
  119.                        /* result                                        */
  120.  
  121. return(WinRegisterClass(hAB, "BarChart", BarChartWndProc, CS_SYNCPAINT | CS_SIZEREDRAW, USER_CWINDOWWORDS));
  122.  
  123. }
  124. #pragma subtitle("   Bar Chart Control DLL - Query Control Information Function")
  125. #pragma page ( )
  126.  
  127. /* --- BarChartQuery ----------------------------------- [ Public ] --- */
  128. /*                                                                      */
  129. /*     This function is used to return to the caller information        */
  130. /*     regarding the installable control and its capabilities.  The     */
  131. /*     function should return a true value otherwise Resource           */
  132. /*     Editor will not register the control as being usable.            */
  133. /*                                                                      */
  134. /*     Upon Entry:                                                      */
  135. /*                                                                      */
  136. /*     PUSERINFO pUserInfo; = User Information Pointer                  */
  137. /*                                                                      */
  138. /*     Upon Exit:                                                       */
  139. /*                                                                      */
  140. /*     BarChartQuery =  TRUE : User Information Being Returned          */
  141. /*                   = FALSE : No User Information Available            */
  142. /*                                                                      */
  143. /* -------------------------------------------------------------------- */
  144.  
  145. BOOL EXPENTRY BarChartQuery(PUSERINFO pUserInfo)
  146.  
  147. {
  148.                        /* Complete the User Information structure       */
  149.                        /* passed to the function by Resource Editor     */
  150.  
  151.                        /* Complete the version and number of control    */
  152.                        /* types.  In Version 1.00 of PMCX, only one     */
  153.                        /* control type is used.                         */
  154. pUserInfo->ulMajor = 3UL;
  155. pUserInfo->ulMinor = 0UL;
  156.                        /* Complete the author and control classname     */
  157.  
  158. memcpy(pUserInfo->szAuthor,    "Prominare Inc.", 15);
  159. memcpy(pUserInfo->szClassname, "BarChart", 9);
  160. memcpy(pUserInfo->szName,      "BarChart", 9);
  161.  
  162.                        /* Complete the default size and style of the    */
  163.                        /* first user control type                       */
  164.  
  165. pUserInfo->utDefined[0].cx         = 100L;
  166. pUserInfo->utDefined[0].cy         = 100L;
  167. pUserInfo->utDefined[0].flStyle    = WS_VISIBLE;
  168.  
  169.                        /* Set the maximum amount of text control can    */
  170.                        /* accept including NULL termination byte        */
  171.  
  172. pUserInfo->utDefined[0].cMaxText     = CCHTEXTMAX;
  173.  
  174.                        /* Save the style's dialogue ID, type, control   */
  175.                        /* data size and count of style masks            */
  176.  
  177. pUserInfo->utDefined[0].idDlg        = DLG_CTRLUSER;
  178. pUserInfo->utDefined[0].ulType       = UTYPE_PRIVATE;
  179. pUserInfo->utDefined[0].flOptions    = PMCXOPT_VARICDATA | PMCXOPT_REFRESH;
  180. pUserInfo->utDefined[0].cCtlData     = 0UL;
  181. pUserInfo->utDefined[0].cMasks       = 0UL;
  182. pUserInfo->utDefined[0].flStyleType  = STYLETYPE_BITFLAGS;
  183.  
  184.                        /* Save the description of the control           */
  185.  
  186. memcpy(pUserInfo->utDefined[0].szDescription, "Bar Chart", 10);
  187.  
  188.                        /* Return the success flag back to Resource      */
  189.                        /* Editor                                        */
  190. return(TRUE);
  191. }
  192. #pragma subtitle("   Bar Chart Control DLL - Set Long Value Function")
  193. #pragma page( )
  194.  
  195. /* --- SetDlgItemLong --------------------------------- [ Private ] --- */
  196. /*                                                                      */
  197. /*     This function is used to complement the WinSetDlgItemShort       */
  198. /*     function by providing a LONG equivalent.                         */
  199. /*                                                                      */
  200. /*     Upon Entry:                                                      */
  201. /*                                                                      */
  202. /*     HWND  hwndDlg; = Dialogue Window Handle                          */
  203. /*     ULONG idItem;  = Item ID                                         */
  204. /*     ULONG ulValue; = Long Value                                      */
  205. /*     BOOL  fSigned; = Signed Flag                                     */
  206. /*                                                                      */
  207. /*     Upon Exit:                                                       */
  208. /*                                                                      */
  209. /*     SetDlgItemLong =  TRUE : Successfully Set Value                  */
  210. /*                    = FALSE : Error Occurred                          */
  211. /*                                                                      */
  212. /* -------------------------------------------------------------------- */
  213.  
  214. BOOL EXPENTRY SetDlgItemLong(HWND hwndDlg, ULONG idItem, ULONG ulValue, BOOL fSigned)
  215.  
  216. {
  217. CHAR szNumBuf[32];                 /* Character Buffer                  */
  218.  
  219. return(WinSetDlgItemText(hwndDlg, idItem, fSigned ? _ltoa((LONG)ulValue, szNumBuf, 10) : _ultoa(ulValue, szNumBuf, 10)));
  220. }
  221. #pragma subtitle("   Bar Chart Control DLL - Get Long Value Function")
  222. #pragma page( )
  223.  
  224. /* --- QueryDlgItemLong ------------------------------- [ Private ] --- */
  225. /*                                                                      */
  226. /*     This function is used to complement the WinSetDlgItemShort       */
  227. /*     function by providing a LONG equivalent.                         */
  228. /*                                                                      */
  229. /*     Upon Entry:                                                      */
  230. /*                                                                      */
  231. /*     HWND  hwndDlg; = Dialogue Window Handle                          */
  232. /*     ULONG idItem;  = Item ID                                         */
  233. /*     ULONG ulValue; = Long Value                                      */
  234. /*     BOOL  fSigned; = Signed Flag                                     */
  235. /*                                                                      */
  236. /*     Upon Exit:                                                       */
  237. /*                                                                      */
  238. /*     QueryDlgItemLong =  TRUE : Successfully Retrived Value           */
  239. /*                      = FALSE : Error Occurred                        */
  240. /*                                                                      */
  241. /* -------------------------------------------------------------------- */
  242.  
  243. BOOL EXPENTRY QueryDlgItemLong(HWND hwndDlg, ULONG idItem, PLONG pResult, BOOL fSigned)
  244.  
  245. {
  246. CHAR  szNumBuf[32];                /* Character Buffer                  */
  247. PCHAR pch;                         /* String Character Pointer          */
  248.  
  249.                        /* Try to get the text from the item specified   */
  250.  
  251. if ( WinQueryDlgItemText(hwndDlg, idItem, 32L, szNumBuf) )
  252.    {
  253.                        /* Check to see if the item is to be signed or   */
  254.                        /* unsigned, and when unsigned, strip out the    */
  255.                        /* minus sign                                    */
  256.  
  257.    if ( !fSigned && (pch = strchr(szNumBuf, '-')) )
  258.        *pch = (CHAR)' ';
  259.                        /* Convert the string to a number and return the */
  260.                        /* value back through the long pointer           */
  261.  
  262.    *pResult = atol(szNumBuf);
  263.    return(TRUE);
  264.    }
  265. else
  266.    {
  267.    *pResult = 0L;
  268.    return(FALSE);
  269.    }
  270. }
  271. #pragma subtitle("   Bar Chart Control DLL - Control Data Decoding Procedure")
  272. #pragma page ( )
  273.  
  274. /* --- InitNotebookPageData --------------------------- [ Private ] --- */
  275. /*                                                                      */
  276. /*     This function is used to decode the control data for the         */
  277. /*     bar chart and place it within the appropriate controls           */
  278. /*     within the styles dialogue.                                      */
  279. /*                                                                      */
  280. /*     Upon Entry:                                                      */
  281. /*                                                                      */
  282. /*     HWND           hWnd;  = Dialogue Window Handle                   */
  283. /*     PBARCHARTCDATA pbccd; = Bar Chart CLTDATA Pointer                */
  284. /*                                                                      */
  285. /*     Upon Exit:                                                       */
  286. /*                                                                      */
  287. /*     Nothing                                                          */
  288. /*                                                                      */
  289. /* -------------------------------------------------------------------- */
  290.  
  291. VOID InitBarChartData(HWND hWnd, PBARCHARTCDATA pbccd)
  292.  
  293. {
  294. CHAR   szBuffer[256];              /* Buffer                            */
  295. INT    cLen;                       /* Text Length                       */
  296. IPT    iptData1;                   /* MLE Data Start Position           */
  297. IPT    iptData2;                   /* MLE Data Start Position           */
  298. PULONG pulValues;                  /* Values Array                      */
  299. PBYTE  pb;                         /* List Pointer                      */
  300. register INT i, n;                 /* Loop Counters                     */
  301.  
  302.                        /* Set the item count in the Items entry field   */
  303.  
  304. SetDlgItemLong(hWnd, EF_ITEMS, (ULONG)pbccd->cItems, TRUE);
  305.  
  306.                        /* Set the vertical scale text                   */
  307.  
  308. WinSetDlgItemText(hWnd, EF_VERTTITLE, pbccd->cbVertTitle ? PSZVERTTITLE(pbccd) : "");
  309.  
  310.                        /* Set the horizontal scale text                 */
  311.  
  312. WinSetDlgItemText(hWnd, EF_HORZTITLE, pbccd->cbHorzTitle ? PSZHORZTITLE(pbccd) : "");
  313.  
  314.                        /* Initialize the MLEs before placing scale text */
  315.                        /* and values within them                        */
  316.  
  317. WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_DISABLEREFRESH, 0L, 0L);
  318. WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_RESETUNDO, 0L, 0L);
  319. WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_RESETUNDO, 0L, 0L);
  320. WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_DISABLEREFRESH, 0L, 0L);
  321.  
  322. if ( pbccd->cItems )
  323.    {
  324.    pulValues = PULONGVALUES(pbccd);
  325.  
  326.                        /* Point to the start of the data block that     */
  327.                        /* contains the tab text                         */
  328.  
  329.    pb = PBYTELIST(pbccd);
  330.  
  331.                        /* Walk the array and convert the ID to ASCII    */
  332.                        /* before placing the value on a single line     */
  333.                        /* within the MLE                                */
  334.  
  335.    for ( i = n = 0, iptData1 = iptData2 = 0L; i < pbccd->cItems; i++ )
  336.        {
  337.        WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_SETIMPORTEXPORT, MPFROMP(szBuffer),
  338.                          MPFROMLONG(cLen = (INT)strlen(strcat(_ltoa((LONG)pulValues[i], szBuffer, 10), "\n"))));
  339.        WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_IMPORT, MPFROMP(&iptData1), MPFROMLONG(cLen));
  340.  
  341.        WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_SETIMPORTEXPORT, MPFROMP(szBuffer),
  342.                          MPFROMLONG(cLen = (INT)strlen(strcat(strcpy(szBuffer, &pb[n]), "\n"))));
  343.        WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_IMPORT, MPFROMP(&iptData2), MPFROMLONG(cLen));
  344.        n += (INT)strlen(&pb[n]) + 1;
  345.        }
  346.    WinSendDlgItemMsg(hWnd, MLE_VALUES,  MLM_ENABLEREFRESH, 0L, 0L);
  347.    WinSendDlgItemMsg(hWnd, MLE_HORZSCALE,  MLM_ENABLEREFRESH, 0L, 0L);
  348.    }
  349. }
  350. #pragma subtitle("   Bar Chart Control DLL - Control Data Save Procedure")
  351. #pragma page ( )
  352.  
  353. /* --- GetBarChartData -------------------------------- [ Private ] --- */
  354. /*                                                                      */
  355. /*     This function is used query the dialogue controls containing     */
  356. /*     information for the bar chart for their data and create          */
  357. /*     control data for the control.                                    */
  358. /*                                                                      */
  359. /*     Upon Entry:                                                      */
  360. /*                                                                      */
  361. /*     HWND           hWnd;  = Dialogue Window Handle                   */
  362. /*     PNOTEPAGECDATA pnpcd; = Control Data Structure Pointer           */
  363. /*     PUSERSTYLE     pust;  = Control Styles Structure Pointer         */
  364. /*                                                                      */
  365. /*     Upon Exit:                                                       */
  366. /*                                                                      */
  367. /*     Nothing                                                          */
  368. /*                                                                      */
  369. /* -------------------------------------------------------------------- */
  370.  
  371. VOID GetBarChartData(HWND hWnd, PBARCHARTCDATA pbccd, PUSERSTYLE pust)
  372.  
  373. {
  374. CHAR   szBuffer[CCHMAXPATH];       /* Buffer                            */
  375. INT    cLen;                       /* Text Length                       */
  376. INT    cTextLen;                   /* Text Length                       */
  377. IPT    iptData;                    /* MLE Data Start Position           */
  378. PCHAR  pch;                        /* Scale Text Pointer                */
  379. LONG   cLines;                     /* Lines Count                       */
  380. LONG   cItems = 0L;                /* Item Count                        */
  381. PULONG pulValues;                  /* Values Array                      */
  382. LONG   cVertTitle;                 /* Verticle Title Length             */
  383. LONG   cHorzTitle;                 /* Horizontal Title Length           */
  384. PCHAR  pchScale;                   /* Scale Item Text Pointer           */
  385. LONG   cScales;                    /* Scales Count                      */
  386. register INT i, n;                 /* Loop Counters                     */
  387.  
  388.                        /* Get the number of items that are to be part   */
  389.                        /* of the bar chart                              */
  390.  
  391. QueryDlgItemLong(hWnd, EF_ITEMS, (PLONG)(PVOID)&cItems, TRUE);
  392.  
  393.                        /* Set the vertical scale text length            */
  394.  
  395. if ( (cVertTitle = WinQueryDlgItemTextLength(hWnd, EF_VERTTITLE)) != 0 )
  396.    ++cVertTitle;
  397.                        /* Set the horizontal scale text length          */
  398.  
  399. if ( (cHorzTitle = WinQueryDlgItemTextLength(hWnd, EF_HORZTITLE)) != 0 )
  400.    ++cHorzTitle;
  401.                        /* Get the number of lines within the dialogue   */
  402.                        /* ID's MLE                                      */
  403.  
  404. cLines = SHORT1FROMMR(WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_QUERYLINECOUNT, 0L, 0L));
  405.  
  406.                        /* Allocate scratch memory for the dialogue ID   */
  407.                        /* array                                         */
  408.  
  409. pulValues = (PULONG)malloc((ULONG)(cItems < cLines ? cLines * sizeof(ULONG) : cItems * sizeof(ULONG)));
  410.  
  411.                        /* Get each line from the MLE and convert the    */
  412.                        /* dialogue ID from ASCII to binary              */
  413.  
  414. for ( i = n = cItems = 0, iptData = 0L; i < cLines; i++ )
  415.    if ( (cLen = (INT)(cTextLen = (LONG)WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_QUERYLINELENGTH, MPFROMLONG(iptData), 0L))) != 0 )
  416.        {
  417.                        /* Get the line from the MLE                     */
  418.  
  419.        WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_SETIMPORTEXPORT, MPFROMP(szBuffer), MPFROMLONG((IPT)cTextLen));
  420.        WinSendDlgItemMsg(hWnd, MLE_VALUES, MLM_EXPORT, MPFROMP(&iptData), MPFROMP(&cTextLen));
  421.  
  422.                        /* Terminate the text at the carriage return or  */
  423.                        /* line feed mark                                */
  424.  
  425.        szBuffer[cLen] = (CHAR)0;
  426.        if ( (pch = strchr(szBuffer, '\r')) != NULL )
  427.            *pch = (CHAR)0;
  428.        else
  429.            if ( (pch = strchr(szBuffer, '\n')) != NULL )
  430.                *pch = (CHAR)0;
  431.  
  432.                        /* Convert the ASCII dialogue ID to binary and   */
  433.                        /* save within the scratch ID array              */
  434.  
  435.        if ( szBuffer[0] )
  436.            pulValues[cItems++] = (ULONG)atol(szBuffer);
  437.        }
  438.                        /* Get the number of lines within the tab text   */
  439.                        /* MLE                                           */
  440.  
  441. cLines = SHORT1FROMMR(WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_QUERYLINECOUNT, 0L, 0L));
  442.  
  443.                        /* Allocate scratch memory for the tab text      */
  444.  
  445. memset(pchScale = (PCHAR)malloc(16384), 0, 16384);
  446.  
  447.                        /* Get each line from the MLE and save the text  */
  448.                        /* within the tab text block                     */
  449.  
  450. for ( i = n = 0, cScales = iptData = 0L; i < cLines; i++ )
  451.    if ( (cLen = (INT)(cTextLen = (LONG)WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_QUERYLINELENGTH, MPFROMLONG(iptData), 0L))) != 0 )
  452.        {
  453.        WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_SETIMPORTEXPORT, MPFROMP(szBuffer), MPFROMLONG((IPT)cTextLen));
  454.        WinSendDlgItemMsg(hWnd, MLE_HORZSCALE, MLM_EXPORT, MPFROMP(&iptData), MPFROMP(&cTextLen));
  455.  
  456.        szBuffer[cLen] = (CHAR)0;
  457.        if ( (pch = strchr(szBuffer, '\r')) != NULL )
  458.            *pch = (CHAR)0;
  459.        else
  460.            if ( (pch = strchr(szBuffer, '\n')) != NULL )
  461.                *pch = (CHAR)0;
  462.  
  463.                        /* Copy the text into the tab text block         */
  464.  
  465.        if ( szBuffer[0] )
  466.            {
  467.            n += (INT)strlen(strcpy(&pchScale[n], szBuffer)) + 1;
  468.            ++cScales;
  469.            }
  470.        }
  471.  
  472. if ( cScales != cItems )
  473.    n += cItems - cScales;
  474.  
  475.                        /* Reallocate the memory for the control data    */
  476.                        /* based upon the needs of the data just         */
  477.                        /* retrieved from the MLE's                      */
  478.  
  479. if ( !(pust->pbCtlData = (PBYTE)pust->pfnRealloc(pust->pbCtlData, cHorzTitle + cVertTitle + cItems * sizeof(ULONG) +
  480.                                                  n + sizeof(BARCHARTCDATA) - 1L)) )
  481.    WinMessageBox(HWND_DESKTOP, hWnd, "Memory error on reallocating control data!", "Bar Chart Control", 0UL, MB_OK | MB_ICONEXCLAMATION);
  482. else
  483.    {
  484.                        /* Save the number of bytes within the control   */
  485.                        /* data within the user styles info              */
  486.  
  487.    pust->cbCtlData = (ULONG)(cHorzTitle + cVertTitle + cItems * sizeof(ULONG) + n + sizeof(BARCHARTCDATA) - 1L);
  488.  
  489.                        /* Point to the control data block               */
  490.  
  491.    pbccd = (PBARCHARTCDATA)pust->pbCtlData;
  492.  
  493.                        /* Save the size of the control data block       */
  494.                        /* within the block start as required by OS/2 PM */
  495.  
  496.    pbccd->cb = pust->cbCtlData;
  497.  
  498.                        /* Get the title text if entered                 */
  499.  
  500.    if ( (pbccd->cbVertTitle = cVertTitle) != 0UL )
  501.        WinQueryDlgItemText(hWnd, EF_VERTTITLE, cVertTitle, PSZVERTTITLE(pbccd));
  502.    if ( (pbccd->cbHorzTitle = cHorzTitle) != 0UL )
  503.        WinQueryDlgItemText(hWnd, EF_HORZTITLE, cHorzTitle, PSZHORZTITLE(pbccd));
  504.  
  505.                        /* Copy the values to the control data block     */
  506.  
  507.    if ( (pbccd->cItems = cItems) != 0UL )
  508.        memcpy(PULONGVALUES(pbccd), pulValues, (UINT)(cItems * sizeof(ULONG)));
  509.  
  510.    if ( n )
  511.        memcpy(PBYTELIST(pbccd), pchScale, (UINT)n);
  512.    }
  513.                        /* Release the scratch memory used for the       */
  514.                        /* values and scale text                         */
  515. free(pchScale);
  516. free(pulValues);
  517. }
  518. #pragma subtitle("   Bar Chart Control DLL - Control Styles Dialogue Procedure")
  519. #pragma page ( )
  520.  
  521. /* --- BarChartStyles ---------------------------------- [ Public ] --- */
  522. /*                                                                      */
  523. /*     This function is used for the custom control's styles dialogue   */
  524. /*     box procedure.                                                   */
  525. /*                                                                      */
  526. /*     When the dialogue is invoked from Resource Editor, the           */
  527. /*     address of the user style information is contained in message    */
  528. /*     parameter 2.  The dialogue is responsible for saving the         */
  529. /*     address.  The best method to do this is to save the pointer      */
  530. /*     in the dialogue's reserved memory where it can be retrieved as   */
  531. /*     needed.                                                          */
  532. /*                                                                      */
  533. /*     Upon Entry:                                                      */
  534. /*                                                                      */
  535. /*     HWND   hWnd; = Dialog Window Handle                              */
  536. /*     ULONG  msg;  = PM Message                                        */
  537. /*     MPARAM mp1;  = Message Parameter 1                               */
  538. /*     MPARAM mp2;  = Message Parameter 2                               */
  539. /*                                                                      */
  540. /*     Upon Exit:                                                       */
  541. /*                                                                      */
  542. /*     BarChartStyles = Message Handling Result                         */
  543. /*                                                                      */
  544. /* -------------------------------------------------------------------- */
  545.  
  546. MRESULT EXPENTRY BarChartStyles(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  547.  
  548. {
  549. PUSERSTYLE   pust;                 /* User Style Pointer                */
  550. SWP          swp;                  /* Screen Window Position Holder     */
  551.  
  552. switch ( msg )
  553.    {
  554.                        /* Perform dialogue initialization               */
  555.    case WM_INITDLG :
  556.                        /* Save the pointer to user style information    */
  557.                        /* within the dialog's reserved memory           */
  558.  
  559.        WinSetWindowPtr(hWnd, QWL_USER, (PVOID)mp2);
  560.  
  561.                        /* Get the pointer to the user style information */
  562.  
  563.        if ( (pust = (PUSERSTYLE)mp2) != NULL )
  564.            {
  565.                        /* Set the text, ID symbol and value for the     */
  566.                        /* control                                       */
  567.  
  568.            WinSetDlgItemText(hWnd, EF_TEXT, pust->pszText);
  569.            pust->pfnSetSymbolID(hWnd, IDBX_SYMBOLVALUE, pust);
  570.  
  571.            if ( pust->flStyle & WS_VISIBLE )
  572.                WinSendDlgItemMsg(hWnd, CB_VISIBLE, BM_SETCHECK, MPFROMSHORT(TRUE), 0L);
  573.  
  574.            if ( pust->flStyle & WS_GROUP )
  575.                WinSendDlgItemMsg(hWnd, CB_GROUP, BM_SETCHECK, MPFROMSHORT(TRUE), 0L);
  576.  
  577.            if ( pust->flStyle & WS_DISABLED )
  578.                WinSendDlgItemMsg(hWnd, CB_DISABLED, BM_SETCHECK, MPFROMSHORT(TRUE), 0L);
  579.  
  580.            if ( pust->flStyle & WS_TABSTOP )
  581.                WinSendDlgItemMsg(hWnd, CB_TABSTOP, BM_SETCHECK, MPFROMSHORT(TRUE), 0L);
  582.  
  583.            if ( pust->pbCtlData )
  584.                InitBarChartData(hWnd, (PBARCHARTCDATA)pust->pbCtlData);
  585.            }
  586.                        /* Centre dialog on the screen                   */
  587.  
  588.        WinQueryWindowPos(hWnd, (PSWP)&swp);
  589.        WinSetWindowPos(hWnd, HWND_TOP, (WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN) - swp.cx) / 2L,
  590.                        (WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN) - swp.cy) / 2L, 0L, 0L, SWP_MOVE);
  591.        break;
  592.                        /* Process push button selections                */
  593.    case WM_COMMAND :
  594.        switch ( SHORT1FROMMP(mp1) )
  595.            {
  596.                        /* Presentation push button selected             */
  597.  
  598.            case DID_FONTCLR :
  599.  
  600.                        /* Get the pointer to the user style information */
  601.  
  602.                if ( (pust = PDATAFROMDLG(hWnd)) != NULL )
  603.  
  604.                        /* Get the address of the look up function from  */
  605.                        /* user style information structure and display  */
  606.                        /* the dialog.  The value selected within the    */
  607.                        /* dialog will be automatically placed within    */
  608.                        /* the required entry fields                     */
  609.  
  610.                    pust->pfnGetFontClr(hWnd);
  611.                break;
  612.                        /* Enter pushbutton selected get the definitions */
  613.                        /* for the control                               */
  614.            case DID_OK :
  615.  
  616.                        /* Get the pointer to the user style information */
  617.  
  618.                if ( (pust = PDATAFROMDLG(hWnd)) != NULL )
  619.                    {
  620.                        /* Get the address of the symbol validation      */
  621.                        /* function from the user style information      */
  622.                        /* structure.  The function will validate the    */
  623.                        /* symbol and will check for duplications of     */
  624.                        /* values.  A return value of TRUE from the      */
  625.                        /* validation function indicates that the symbol */
  626.                        /* and value are acceptable.  Conversely, a      */
  627.                        /* FALSE return value indicates that symbol or   */
  628.                        /* value was not acceptable.  In this case,      */
  629.                        /* the dialog should not be exited from and the  */
  630.                        /* values within the entry fields should not be  */
  631.                        /* saved.                                        */
  632.  
  633.                    if ( !pust->pfnGetSymbolID(hWnd, IDBX_SYMBOLVALUE, pust) )
  634.                        break;
  635.                    else
  636.                        {
  637.                        /* Symbol and value validated, get the text of   */
  638.                        /* the control and save within the user style    */
  639.                        /* information structure for use by Resource     */
  640.                        /* Editor                                        */
  641.  
  642.                        pust->cText = WinQueryDlgItemText(hWnd, EF_TEXT, CCHTEXTMAX, pust->pszText);
  643.  
  644.                        /* Mask out current styles clearing selectable   */
  645.                        /* styles and save new style                     */
  646.  
  647.                        pust->flStyle = 0UL;
  648.  
  649.                        if ( WinSendDlgItemMsg(hWnd, CB_VISIBLE, BM_QUERYCHECK, 0L, 0L) )
  650.                            pust->flStyle |= WS_VISIBLE;
  651.  
  652.                        if ( WinSendDlgItemMsg(hWnd, CB_GROUP, BM_QUERYCHECK, 0L, 0L) )
  653.                            pust->flStyle |= WS_GROUP;
  654.  
  655.                        if ( WinSendDlgItemMsg(hWnd, CB_DISABLED, BM_QUERYCHECK, 0L, 0L) )
  656.                            pust->flStyle |= WS_DISABLED;
  657.  
  658.                        if ( WinSendDlgItemMsg(hWnd, CB_TABSTOP, BM_QUERYCHECK, 0L, 0L) )
  659.                            pust->flStyle |= WS_TABSTOP;
  660.  
  661.                        GetBarChartData(hWnd, (PBARCHARTCDATA)pust->pbCtlData, pust);
  662.                        }
  663.                    }
  664.                        /* Exit the dialogue indicating changes made     */
  665.  
  666.                WinDismissDlg(hWnd, TRUE);
  667.                break;
  668.                        /* Cancel selected, exit the dialogue without    */
  669.                        /* changing anything                             */
  670.  
  671.            case DID_CANCEL :
  672.                WinDismissDlg(hWnd, FALSE);
  673.                break;
  674.            }
  675.        break;
  676.                        /* Close received, exit dialog                   */
  677.    case WM_CLOSE :
  678.        WinDismissDlg(hWnd, FALSE);
  679.        break;
  680.                        /* Pass through unhandled messages               */
  681.    default :
  682.        return(WinDefDlgProc(hWnd, msg, mp1, mp2));
  683.    }
  684. return(0L);
  685.  
  686. }
  687. #pragma subtitle("   Bar Chart Control DLL - Control Window Procedure")
  688. #pragma page( )
  689.  
  690. /* --- lGetPresParam ---------------------------------- [ Private } --- */
  691. /*                                                                      */
  692. /*     This function is used to retrieve a presentation parameter       */
  693. /*     that may be present.  If the presentation parameter is not,      */
  694. /*     the default colour passed to the function will be used.          */
  695. /*                                                                      */
  696. /*     Upon Entry:                                                      */
  697. /*                                                                      */
  698. /*     HWND  hWnd;     = Window Handle                                  */
  699. /*     ULONG ulID1;    = Presentation Parameter 1 ID                    */
  700. /*     ULONG ulID2;    = Presentation Parameter 2 ID                    */
  701. /*     LONG  lDefault; = Default Colour                                 */
  702. /*                                                                      */
  703. /*     Upon Exit:                                                       */
  704. /*                                                                      */
  705. /*     lGetPresParam = Colour to Use                                    */
  706. /*                                                                      */
  707. /* -------------------------------------------------------------------- */
  708.  
  709. LONG lGetPresParam(HWND hWnd, ULONG ulID1, ULONG ulID2, LONG lDefault)
  710.  
  711. {
  712. HPS   hPS;                         /* Presentation Space Handle         */
  713. LONG  lClr;                        /* Presentation Parameter Colour     */
  714. ULONG ulID;                        /* Presentation Parameter ID         */
  715.  
  716. if ( WinQueryPresParam(hWnd, ulID1, ulID2, &ulID, 4UL, (PVOID)&lClr, QPF_NOINHERIT | QPF_ID2COLORINDEX | QPF_PURERGBCOLOR) )
  717.    return(lClr);
  718. else
  719.    if ( (lDefault >= SYSCLR_SHADOWHILITEBGND) && (lDefault <= SYSCLR_HELPHILITE) )
  720.        return(WinQuerySysColor(HWND_DESKTOP, lDefault, 0L));
  721.    else
  722.        if ( (lClr = GpiQueryRGBColor(hPS = WinGetPS(hWnd), LCOLOPT_REALIZED, lDefault)) == GPI_ALTERROR )
  723.            {
  724.            WinReleasePS(hPS);
  725.            return(lDefault);
  726.            }
  727.        else
  728.            {
  729.            WinReleasePS(hPS);
  730.            return(lClr);
  731.            }
  732. }
  733. #pragma subtitle("   Bar Chart Control DLL - Control Window Sizing Procedure")
  734. #pragma page ( )
  735.  
  736. /* --- ulNiceScale ------------------------------------ [ Private ] --- */
  737. /*                                                                      */
  738. /*     This function is used to determine the maximum value for the     */
  739. /*     scale.                                                           */
  740. /*                                                                      */
  741. /*     Upon Entry:                                                      */
  742. /*                                                                      */
  743. /*     ULONG ulMax; = Maximum Value                                     */
  744. /*                                                                      */
  745. /*     Upon Exit:                                                       */
  746. /*                                                                      */
  747. /*     ulNiceScale = Scale Limit                                        */
  748. /*                                                                      */
  749. /* -------------------------------------------------------------------- */
  750.  
  751. ULONG ulNiceScale(ULONG ulMax)
  752.  
  753. {
  754. double dMax = (double)ulMax;       /* Maximum Value                     */
  755. double dRange;                     /* Range                             */
  756. double dMagnitude = 0.0;           /* Magnitude                         */
  757.  
  758. if ( (dRange = fabs(dRange)) >= 1.0 )
  759.    while ( dRange >= 10.0)
  760.        {
  761.        dRange /= 10.0;
  762.        dMagnitude++;
  763.        }
  764. else
  765.    while ( dRange <= 1.0 )
  766.        {
  767.        dRange *= 10.0;
  768.        dMagnitude--;
  769.        }
  770. dRange = pow(10.0, dMagnitude);
  771.  
  772. return((ULONG)((ceil(dMax / dRange)) * dRange));
  773.  
  774. }
  775. #pragma subtitle("   Bar Chart Control DLL - Control Window Sizing Procedure")
  776. #pragma page ( )
  777.  
  778. /* --- CalcSize --------------------------------------- [ Private ] --- */
  779. /*                                                                      */
  780. /*     This function is used to calculate the sizes and positions       */
  781. /*     of the various elements that are used to make up the bar         */
  782. /*     chart.                                                           */
  783. /*                                                                      */
  784. /*     Upon Entry:                                                      */
  785. /*                                                                      */
  786. /*     HWND      hWnd; = Window Handle                                  */
  787. /*     PRECTL    prcl; = Control Rectangle Pointer                      */
  788. /*     PBARCHART pbc;  = Bar Chart Data Pointer                         */
  789. /*                                                                      */
  790. /*     Upon Exit:                                                       */
  791. /*                                                                      */
  792. /*     Nothing                                                          */
  793. /*                                                                      */
  794. /* -------------------------------------------------------------------- */
  795.  
  796. static VOID CalcSize(HWND hWnd, PRECTL prcl, PBARCHART pbc)
  797.  
  798. {
  799. CHAR        szBuffer[32];          /* String Buffer                     */
  800. FONTMETRICS fm;                    /* Font Metrics                      */
  801. HPS         hPS;                   /* Presentation Space Handle         */
  802. LONG        cxAvgChar;             /* Average Character Width           */
  803. LONG        cxBar;                 /* Bar Width                         */
  804. LONG        cyBar;                 /* Bar Height                        */
  805. LONG        cyFont;                /* Font Height                       */
  806. LONG        cyScaleText;           /* Scale Text Height                 */
  807. LONG        lScale;                /* Scale Factor                      */
  808. LONG        xStart;                /* Bar Starting Point                */
  809. POINTL      rgptl[TXTBOX_COUNT];   /* Text Box Point Array              */
  810. ULONG       ul;                    /* Chart High Water Mark             */
  811. register INT i;                    /* Loop Counter                      */
  812.  
  813. pbc->fDraw = TRUE;
  814.  
  815.                        /* Get the font metrics for the control          */
  816.  
  817. GpiQueryFontMetrics(hPS = WinGetPS(hWnd), sizeof(FONTMETRICS), &fm);
  818. WinReleasePS(hPS);
  819.                        /* Save the average character width of the       */
  820.                        /* default font                                  */
  821.  
  822. cxAvgChar = fm.lAveCharWidth;
  823.  
  824.                        /* Calculate the top edge of the bar chart       */
  825.                        /* making sure that the bar char title text is   */
  826.                        /* taken into consideration                      */
  827.  
  828. pbc->aptl[2].x = pbc->aptl[3].x = prcl->xRight - 1L;
  829. if ( pbc->cTitleText )
  830.    {
  831.    pbc->rclTitleText = *prcl;
  832.    pbc->rclTitleText.yBottom = (pbc->aptl[1].y = pbc->aptl[2].y = prcl->yTop - (cyFont = fm.lMaxBaselineExt * 2L) - 1L) + 1L;
  833.    }
  834. else
  835.    pbc->aptl[1].y = pbc->aptl[2].y = prcl->yTop - 1L;
  836.  
  837.                        /* Calculate the bottom edge of the bar chart    */
  838.                        /* making sure that the horizontal scale text is */
  839.                        /* taken into consideration                      */
  840. if ( pbc->cHorzText )
  841.    {
  842.    pbc->rclHorzText = *prcl;
  843.    pbc->rclHorzText.yTop = (pbc->aptl[0].y = pbc->aptl[3].y = prcl->yBottom + fm.lMaxBaselineExt * 3L) - ((fm.lMaxBaselineExt * 3L) / 2L) - 1L;
  844.    }
  845. else
  846.    pbc->aptl[0].y = pbc->aptl[3].y = prcl->yBottom;
  847.  
  848.                        /* Calculate the left edge of the bar chart      */
  849.                        /* making sure that the vertical scale text is   */
  850.                        /* taken into consideration                      */
  851. if ( pbc->cVertText )
  852.    {
  853.                        /* Since the vertical text is vertically         */
  854.                        /* oriented, set the font for the text and get   */
  855.                        /* the font metrics to allow the proper          */
  856.                        /* calculation of the left edge of the bar chart */
  857.  
  858.    GpiSetCharBox(hPS = WinGetPS(hWnd), &pbc->sizfx);
  859.    GpiCreateLogFont(hPS, (PSTR8)NULL, 4L, &pbc->fat);
  860.    GpiSetCharSet(hPS, 4L);
  861.  
  862.    GpiSetCharAngle(hPS, &gradl);
  863.    GpiQueryFontMetrics(hPS, sizeof(FONTMETRICS), &fm);
  864.    WinReleasePS(hPS);
  865.  
  866.    pbc->rclVertText = *prcl;
  867.    pbc->rclVertText.xRight = (pbc->aptl[0].x = pbc->aptl[1].x = prcl->xLeft + (fm.lMaxBaselineExt * 2L)) - 1L;
  868.    }
  869. else
  870.    pbc->aptl[0].x = pbc->aptl[1].x = prcl->xLeft;
  871.  
  872.                        /* Determine the high water mark of the values   */
  873.  
  874. for ( i = 0, ul = 0UL; i < pbc->cItems; i++ )
  875.    if ( pbc->pbci[i].ulValue > ul )
  876.        ul = pbc->pbci[i].ulValue;
  877.  
  878. ul = ulNiceScale(ul);
  879.                        /* Calculate the number of vertical scale items  */
  880.  
  881. pbc->cScales = (lScale = (cyBar = (pbc->aptl[1].y - 1) - (pbc->aptl[0].y + 1)) / cyFont);
  882.  
  883. for ( i = pbc->cScales; i > 0; i-- )
  884.    if ( (ul % i) == 0 )
  885.        {
  886.        lScale = ul / (pbc->cScales = i);
  887.        break;
  888.        }
  889.                        /* Form the scale values and placement           */
  890.                        /* positions                                     */
  891.  
  892. if ( pbc->cScales != 0 )
  893.    {
  894.                        /* Form the scale values                         */
  895.  
  896.    pbc->psi = (PSCALEITEM)malloc(++pbc->cScales * sizeof(SCALEITEM));
  897.    for ( i = 0; i < pbc->cScales; i++ )
  898.        strcpy(pbc->psi[i].pszLabel = (PSZ)malloc((pbc->psi[i].cLabel = strlen(_ltoa(i * lScale, szBuffer, 10))) + 1), szBuffer);
  899.  
  900.                        /* Get the width of the largest scale item       */
  901.  
  902.    GpiQueryTextBox(hPS = WinGetPS(hWnd), pbc->psi[i - 1].cLabel, pbc->psi[i - 1].pszLabel, 5L, rgptl);
  903.    WinReleasePS(hPS);
  904.                        /* Calculate the scale value positions           */
  905.  
  906.    cyScaleText = rgptl[TXTBOX_TOPLEFT].y - rgptl[TXTBOX_BOTTOMLEFT].y;
  907.    for ( i = 0; i < pbc->cScales; i++ )
  908.        {
  909.        pbc->psi[i].rcl.xRight  = (pbc->psi[i].rcl.xLeft   = pbc->aptl[0].x) + rgptl[TXTBOX_CONCAT].x + cxAvgChar - 1L;
  910.        pbc->psi[i].rcl.yTop    = (pbc->psi[i].rcl.yBottom = ((cyBar * i) / (pbc->cScales - 1)) + pbc->aptl[0].y - (cyScaleText / 2L)) + cyScaleText;
  911.        }
  912.    pbc->aptl[0].x += rgptl[TXTBOX_CONCAT].x + cxAvgChar;
  913.    pbc->aptl[1].x += rgptl[TXTBOX_CONCAT].x + cxAvgChar;
  914.    }
  915.                        /* Form the 3D shading points for the chart      */
  916.                        /* area                                          */
  917.  
  918. pbc->aptl[4] = pbc->aptl[0];
  919. pbc->aptl[5].x = pbc->aptl[6].x = pbc->aptl[0].x + 1L;
  920. pbc->aptl[5].y = pbc->aptl[8].y = pbc->aptl[0].y + 1L;
  921. pbc->aptl[7].x = pbc->aptl[8].x = pbc->aptl[2].x - 1L;
  922. pbc->aptl[6].y = pbc->aptl[7].y = pbc->aptl[1].y - 1L;
  923.  
  924.                        /* Calculate the rectangle for the bar chart     */
  925.  
  926. pbc->rcl.xLeft   = pbc->aptl[0].x + 1L;
  927. pbc->rcl.xRight  = pbc->aptl[2].x - 1L;
  928. pbc->rcl.yBottom = pbc->aptl[0].y + 1L;
  929. pbc->rcl.yTop    = pbc->aptl[1].y - 1L;
  930.  
  931. if ( pbc->cItems )
  932.    {
  933.                        /* Calculate the bar widths assuming the gaps    */
  934.                        /* between the bars is the width of a bar        */
  935.  
  936.    xStart = (cxBar = (pbc->rcl.xRight - pbc->rcl.xLeft) / (pbc->cItems * 2)) / 2L + pbc->aptl[0].x + 1L;
  937.  
  938.                        /* For each bar chart item, determine the bar    */
  939.                        /* drawing points                                */
  940.  
  941.    for ( i = 0; i < pbc->cItems; i++ )
  942.        {
  943.        pbc->pbci[i].aptl[2].x = pbc->pbci[i].aptl[3].x = (pbc->pbci[i].aptl[0].x = pbc->pbci[i].aptl[1].x = xStart) + cxBar;
  944.        xStart += (cxBar * 2L);
  945.        pbc->pbci[i].aptl[0].y = pbc->pbci[i].aptl[3].y = pbc->aptl[0].y + 1L;
  946.        pbc->pbci[i].aptl[1].y = pbc->pbci[i].aptl[2].y = pbc->aptl[0].y + (pbc->pbci[i].ulValue * cyBar) / ul;
  947.        pbc->pbci[i].rcl.xLeft   = pbc->pbci[i].aptl[0].x + 1L;
  948.        pbc->pbci[i].rcl.xRight  = pbc->pbci[i].aptl[2].x;
  949.        pbc->pbci[i].rcl.yBottom = pbc->pbci[i].aptl[0].y + 1L;
  950.        pbc->pbci[i].rcl.yTop    = pbc->pbci[i].aptl[2].y;
  951.  
  952.        pbc->pbci[i].rclLabel.xLeft   = pbc->pbci[i].aptl[0].x - (cxBar / 2L);
  953.        pbc->pbci[i].rclLabel.xRight  = pbc->pbci[i].aptl[3].x + (cxBar / 2L);
  954.        pbc->pbci[i].rclLabel.yBottom = pbc->pbci[i].aptl[0].y - cyFont;
  955.        pbc->pbci[i].rclLabel.yTop    = pbc->pbci[i].aptl[0].y - 1L;
  956.        }
  957.    }
  958. }
  959. #pragma subtitle("   Bar Chart Control DLL - CTLDATA Decoding Procedure")
  960. #pragma page ( )
  961.  
  962. /* --- DecodeCTLDATA ---------------------------------- [ Private ] --- */
  963. /*                                                                      */
  964. /*     This function is used to calculate the sizes and positions       */
  965. /*     of the various elements that are used to make up a 3D text       */
  966. /*     field.                                                           */
  967. /*                                                                      */
  968. /*     Upon Entry:                                                      */
  969. /*                                                                      */
  970. /*     HWND      hWnd; = Window Handle                                  */
  971. /*     PRECTL    prcl; = Control Rectangle Pointer                      */
  972. /*     PBARCHART pbc;  = Bar Chart Data Pointer                         */
  973. /*                                                                      */
  974. /*     Upon Exit:                                                       */
  975. /*                                                                      */
  976. /*     Nothing                                                          */
  977. /*                                                                      */
  978. /* -------------------------------------------------------------------- */
  979.  
  980. static VOID DecodeCTLDATA(PBARCHART pbc, PBARCHARTCDATA pbccd)
  981.  
  982. {
  983. PBYTE  pb;                         /* Scale Text Pointer                */
  984. PULONG pulValues;                  /* Values Pointer                    */
  985. register INT i, n;                 /* Loop Counter                      */
  986.  
  987.                        /* Get the horizontal scale title text if        */
  988.                        /* present                                       */
  989.  
  990. if ( (pbc->cHorzText = pbccd->cbHorzTitle) != 0UL )
  991.    memcpy(pbc->pszHorzText = (PSZ)malloc(pbc->cHorzText), PSZHORZTITLE(pbccd), pbccd->cbHorzTitle);
  992.  
  993.                        /* Get the vertical scale title text if present  */
  994.  
  995. if ( (pbc->cVertText = pbccd->cbVertTitle) != 0UL )
  996.    memcpy(pbc->pszVertText = (PSZ)malloc(pbc->cVertText), PSZVERTTITLE(pbccd), pbccd->cbVertTitle);
  997.  
  998.                        /* Get the items of the bar chart along with the */
  999.                        /* item labels                                   */
  1000.  
  1001. if ( (pbc->cItems = pbccd->cItems) != 0UL )
  1002.    {
  1003.    pbc->pbci = (PBARCHARTITEM)malloc(pbc->cItems * sizeof(BARCHARTITEM));
  1004.    pulValues = PULONGVALUES(pbccd);
  1005.    pb = PBYTELIST(pbccd);
  1006.    for ( i = n = 0; i < pbccd->cItems; i++ )
  1007.        {
  1008.        pbc->pbci[i].ulValue = pulValues[i];
  1009.        pbc->pbci[i].pszLabel = (PSZ)malloc(pbc->pbci[i].cLabel = strlen(&pb[n]) + 1);
  1010.        memcpy(pbc->pbci[i].pszLabel, &pb[n], pbc->pbci[i].cLabel);
  1011.        n += pbc->pbci[i].cLabel;
  1012.        }
  1013.    }
  1014. }
  1015. #pragma subtitle("   Bar Chart Control DLL - Image Font Selection Function")
  1016. #pragma page( )
  1017.  
  1018. /* --- lSelectFont ------------------------------------ [ Private ] --- */
  1019. /*                                                                      */
  1020. /*     This function is used to determine the lMatch component for      */
  1021. /*     a requested image font.                                          */
  1022. /*                                                                      */
  1023. /*     Upon Entry:                                                      */
  1024. /*                                                                      */
  1025. /*     CHAR  *pszFacename; = Font Face Name                             */
  1026. /*     LONG  lPoints;      = Points Size Requested                      */
  1027. /*                                                                      */
  1028. /*     Upon Exit:                                                       */
  1029. /*                                                                      */
  1030. /*     lSelectFont = lMatch Number for Requested Font                   */
  1031. /*                                                                      */
  1032. /* -------------------------------------------------------------------- */
  1033.  
  1034. LONG lSelectFont(CHAR *pszFacename, LONG lPoints)
  1035.  
  1036. {
  1037. HDC          hDC;                  /* Display Device Context Handle     */
  1038. HPS          hPS;                  /* Presentation Space Handle         */
  1039. LONG         cFonts;               /* Fonts Count                       */
  1040. LONG         lFontsTotal = 0L;     /* Fonts Total Count                 */
  1041. LONG         lMatch = 1L;          /* Font Match Value                  */
  1042. LONG         lXDeviceRes;          /* x Device Resolution               */
  1043. LONG         lYDeviceRes;          /* y Device Resolution               */
  1044. PFONTMETRICS pfm;                  /* Font Metrics Pointer              */
  1045. register INT i;                    /* Loop Counter                      */
  1046.  
  1047.                        /* Get the height of the screen in pels          */
  1048.  
  1049. DevQueryCaps(hDC = GpiQueryDevice(hPS = WinGetScreenPS(HWND_DESKTOP)), CAPS_HORIZONTAL_FONT_RES, 1L, &lXDeviceRes);
  1050. DevQueryCaps(hDC, CAPS_VERTICAL_FONT_RES,   1L, &lYDeviceRes);
  1051.  
  1052.                        /* Get the number of fonts for the face name     */
  1053.                        /* provided and allocate space for the font      */
  1054.                        /* metrics for the different font sizes and      */
  1055.                        /* devices of the font                           */
  1056.  
  1057. pfm = (PFONTMETRICS)malloc(sizeof(FONTMETRICS) * (cFonts = GpiQueryFonts(hPS, QF_PUBLIC, pszFacename,
  1058.                                                                          &lFontsTotal, sizeof(FONTMETRICS), (PFONTMETRICS)NULL)));
  1059.  
  1060.                        /* Make a pointer for the memory allocated for   */
  1061.                        /* the font metrics and get the font metrics for */
  1062.                        /* the number of fonts for the face name         */
  1063.                        /* provided                                      */
  1064.  
  1065. GpiQueryFonts(hPS, QF_PUBLIC, pszFacename, &cFonts, sizeof(FONTMETRICS), pfm);
  1066.  
  1067.                        /* Release the presentation space acquired to    */
  1068.                        /* determine the screen height and to get the    */
  1069.                        /* font metrics                                  */
  1070. WinReleasePS(hPS);
  1071.                        /* Adjust the point size to correspond to the    */
  1072.                        /* the nominal point size that is contained      */
  1073.                        /* within the font metrics structure             */
  1074. lPoints *= 10;
  1075.                        /* Loop through the font metrics returned to     */
  1076.                        /* locate the desired font by matching the x and */
  1077.                        /* y device resolution of the font and the point */
  1078.                        /* size                                          */
  1079.  
  1080. for ( i = 0; i < (INT)cFonts; i++ )
  1081.    if ( (pfm[i].sXDeviceRes == (SHORT)lXDeviceRes) && (pfm[i].sYDeviceRes == (SHORT)lYDeviceRes) &&
  1082.         ((LONG)pfm[i].sNominalPointSize == lPoints) )
  1083.        {
  1084.                        /* Font found, get the match value to allow the  */
  1085.                        /* exact font to be selected by the calling      */
  1086.                        /* application                                   */
  1087.  
  1088.        lMatch = pfm[i].lMatch;
  1089.        break;
  1090.        }
  1091.                        /* Release the memory allocated for the font     */
  1092.                        /* metrics array                                 */
  1093. DosFreeMem(pfm);
  1094.                        /* Return the match value to the calling         */
  1095.                        /* application                                   */
  1096. return(lMatch);
  1097. }
  1098. #pragma subtitle("   Bar Chart Control DLL - Control Window Procedure")
  1099. #pragma page ( )
  1100.  
  1101. /* --- BarChartWndProc -------------------------------- [ Private ] --- */
  1102. /*                                                                      */
  1103. /*     This function is used to handle the messages sent to the         */
  1104. /*     installed control.  The window procedure is designed to          */
  1105. /*     allow for multiple instances and to be totally re-entrant.       */
  1106. /*                                                                      */
  1107. /*     Upon Entry:                                                      */
  1108. /*                                                                      */
  1109. /*     HWND   hWnd; = Window Handle                                     */
  1110. /*     ULONG  msg;  = PM Message                                        */
  1111. /*     MPARAM mp1;  = Message Parameter 1                               */
  1112. /*     MPARAM mp2;  = Message Parameter 2                               */
  1113. /*                                                                      */
  1114. /*     Upon Exit:                                                       */
  1115. /*                                                                      */
  1116. /*     BarChartWndProc = Message Handling Result                        */
  1117. /*                                                                      */
  1118. /* -------------------------------------------------------------------- */
  1119.  
  1120. MRESULT EXPENTRY BarChartWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  1121.  
  1122. {
  1123. FONTMETRICS    fm;                 /* Font Metrics                      */
  1124. HPS            hPS;                /* Presentation Space Handle         */
  1125. PBARCHART      pbc;                /* Text Field Structure Pointer      */
  1126. PCREATESTRUCT  pcrst;              /* Create Structure Pointer          */
  1127. PWNDPARAMS     pwprm;              /* Window Parameters Pointer         */
  1128. RECTL          rcl;                /* Rectangle Holder                  */
  1129. PBYTE          pb;                 /* List Pointer                      */
  1130. PULONG         pulValues;          /* Values List Pointer               */
  1131. PBARCHARTCDATA pbccd;              /* Bar Chart CTLDATA Pointer         */
  1132. register INT i, n;                 /* Loop Counter                      */
  1133.  
  1134. switch ( msg )
  1135.    {
  1136.  
  1137. /************************************************************************/
  1138. /************************************************************************/
  1139. /*                                                                      */
  1140. /* Part 1: Control creation                                             */
  1141. /*                                                                      */
  1142. /************************************************************************/
  1143. /************************************************************************/
  1144.  
  1145.    /*********************************************************************/
  1146.    /*  Creation sequence                                                */
  1147.    /*********************************************************************/
  1148.  
  1149.    case WM_CREATE :
  1150.                        /* Create a heap for the control using a         */
  1151.                        /* segment                                       */
  1152.  
  1153.        memset(pbc = (PBARCHART)malloc(sizeof(BARCHART)), 0, sizeof(BARCHART));
  1154.  
  1155.                        /* Save the address of the text string pointer   */
  1156.                        /* in the control's reserved memory to allow it  */
  1157.                        /* to be referenced as required by the control   */
  1158.  
  1159.        WinSetWindowPtr(hWnd, QWW_CDATA, (PVOID)pbc);
  1160.  
  1161.                        /* Get the control's creation structure address  */
  1162.                        /* to copy the default text of the control to    */
  1163.                        /* the memory in the heap                        */
  1164.  
  1165.        pcrst = (PCREATESTRUCT)PVOIDFROMMP(mp2);
  1166.  
  1167.                        /* Save the owner window handle                  */
  1168.  
  1169.        pbc->hwndOwner = pcrst->hwndOwner;
  1170.  
  1171.                        /* Check to see if any CTLDATA defined for the   */
  1172.                        /* control and if so, decode it                  */
  1173.        if ( mp1 )
  1174.            DecodeCTLDATA(pbc, (PBARCHARTCDATA)mp1);
  1175.  
  1176.                        /* Since the vertical scale text is vertical,    */
  1177.                        /* need to form the size box for the text based  */
  1178.                        /* on a defined text size, therefore, get the    */
  1179.                        /* font info for Helv and base the size of the   */
  1180.                        /* scalable vertical font on it                  */
  1181.  
  1182.        pbc->fat.usRecordLength = (USHORT)sizeof(FATTRS);
  1183.        pbc->fat.usCodePage     = (USHORT)850;
  1184.        pbc->fat.lMatch         = lSelectFont(memcpy(pbc->fat.szFacename, "Helv", 5UL), 8L);
  1185.        GpiCreateLogFont(hPS = WinGetPS(hWnd), (PSTR8)NULL, 4L, &pbc->fat);
  1186.        GpiSetCharSet(hPS, 4L);
  1187.  
  1188.        GpiQueryFontMetrics(hPS, sizeof(FONTMETRICS), &fm);
  1189.  
  1190.        pbc->sizfx.cx = MAKEFIXED(fm.lEmHeight, 0);
  1191.        pbc->sizfx.cy = MAKEFIXED(fm.lEmInc, 0);
  1192.  
  1193.        GpiSetCharSet(hPS, 0L);
  1194.        GpiDeleteSetId(hPS, 4L);
  1195.        WinReleasePS(hPS);
  1196.  
  1197.        pbc->fat.usRecordLength  = (USHORT)sizeof(FATTRS);
  1198.        pbc->fat.usCodePage      = (USHORT)850;
  1199.        pbc->fat.fsFontUse       = (USHORT)(FATTR_FONTUSE_OUTLINE | FATTR_FONTUSE_TRANSFORMABLE);
  1200.        memcpy(pbc->fat.szFacename, "Helvetica", 10);
  1201.  
  1202.                        /* Get the title text if present                 */
  1203.  
  1204.        if ( pcrst->pszText )
  1205.            strcpy(pbc->pszTitleText = (PSZ)malloc(pbc->cTitleText = strlen(pcrst->pszText) + 1), pcrst->pszText);
  1206.  
  1207.                        /* Initialize the size of the control            */
  1208.        rcl.xLeft   =
  1209.        rcl.yBottom = 0L;
  1210.  
  1211.                        /* If the control has an initial size, determine */
  1212.                        /* the display locations of the bar chart        */
  1213.  
  1214.        if ( (rcl.xRight= pcrst->cx) && (rcl.yTop = pcrst->cy) )
  1215.            CalcSize(hWnd, &rcl, pbc);
  1216.  
  1217.                        /* Get the presentation parameters for the bar   */
  1218.                        /* chart if any are defined otherwise use        */
  1219.                        /* default colours                               */
  1220.  
  1221.        pbc->lClrText       = lGetPresParam(hWnd, PP_FOREGROUNDCOLOR, PP_FOREGROUNDCOLORINDEX, SYSCLR_OUTPUTTEXT);
  1222.        pbc->lClrBackground = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR, PP_BACKGROUNDCOLORINDEX, SYSCLR_DIALOGBACKGROUND);
  1223.        pbc->lClrBorder     = lGetPresParam(hWnd, PP_BORDERCOLOR,     PP_BORDERCOLORINDEX,     SYSCLR_BUTTONDARK);
  1224.        break;
  1225.  
  1226. /************************************************************************/
  1227. /************************************************************************/
  1228. /*                                                                      */
  1229. /* Part 2: Sizing and Placement                                         */
  1230. /*                                                                      */
  1231. /************************************************************************/
  1232. /************************************************************************/
  1233.  
  1234.    /*********************************************************************/
  1235.    /*  Control being resized                                            */
  1236.    /*********************************************************************/
  1237.  
  1238.    case WM_SIZE :
  1239.                        /* Check to see if the control has a size and if */
  1240.                        /* the case, determine the display locations of  */
  1241.                        /* the bar chart                                 */
  1242.  
  1243.        if ( ((LONG)(SHORT)SHORT1FROMMP(mp2) > 0L) && ((LONG)(SHORT)SHORT2FROMMP(mp2) > 0L) )
  1244.            {
  1245.            WinQueryWindowRect(hWnd, &rcl);
  1246.            CalcSize(hWnd, &rcl, (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA));
  1247.            }
  1248.        else
  1249.                        /* Since the control does not have any size,     */
  1250.                        /* it doesn't need to be drawn, therefore, set   */
  1251.                        /* the draw flag to false to prevent             */
  1252.                        /* unncessary drawing attempts                   */
  1253.  
  1254.            pbc->fDraw = FALSE;
  1255.        break;
  1256.  
  1257. /************************************************************************/
  1258. /************************************************************************/
  1259. /*                                                                      */
  1260. /* Part 3: Focus/Enable Management                                      */
  1261. /*                                                                      */
  1262. /************************************************************************/
  1263. /************************************************************************/
  1264.  
  1265.  
  1266. /************************************************************************/
  1267. /************************************************************************/
  1268. /*                                                                      */
  1269. /* Part 4: Text Input/Output and Presentation Parameter Interface       */
  1270. /*                                                                      */
  1271. /************************************************************************/
  1272. /************************************************************************/
  1273.  
  1274.    /*********************************************************************/
  1275.    /*  Process window parameters setting                                */
  1276.    /*********************************************************************/
  1277.  
  1278.    case WM_SETWINDOWPARAMS :
  1279.  
  1280.                        /* Get the address for the windows parameters    */
  1281.                        /* structure                                     */
  1282.  
  1283.        pwprm = (PWNDPARAMS)PVOIDFROMMP(mp1);
  1284.  
  1285.                        /* Check to see if the text for the control is   */
  1286.                        /* being set                                     */
  1287.  
  1288.        if ( pwprm->fsStatus & WPM_TEXT )
  1289.            {
  1290.                        /* Get the address of the control info from the  */
  1291.                        /* control's reserved memory                     */
  1292.  
  1293.            pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1294.  
  1295.                        /* Check to see if any text is being set         */
  1296.  
  1297.            if ( pwprm->cchText )
  1298.                {
  1299.                if ( pbc->cTitleText )
  1300.                    free(pbc->pszTitleText);
  1301.                memcpy(pbc->pszTitleText = (PSZ)malloc(pwprm->cchText + 1), pwprm->pszText, pbc->cTitleText = pwprm->cchText + 1);
  1302.                }
  1303.            else
  1304.                if ( pbc->cTitleText )
  1305.                    {
  1306.                        /* No text is being set, clear any existing text */
  1307.  
  1308.                    free(pbc->pszTitleText);
  1309.                    pbc->cTitleText = 0UL;
  1310.                    }
  1311.  
  1312.            if ( pbc->fDraw )
  1313.                WinInvalidateRect(hWnd, &pbc->rclTitleText, FALSE);
  1314.            return(MRFROMLONG(TRUE));
  1315.            }
  1316.        if ( (pwprm->fsStatus & WPM_CTLDATA) && pwprm->pCtlData )
  1317.            {
  1318.            DecodeCTLDATA(pbc, (PBARCHARTCDATA)pwprm->pCtlData);
  1319.            if ( pbc->fDraw )
  1320.                WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1321.            return(MRFROMLONG(TRUE));
  1322.            }
  1323.        break;
  1324.  
  1325.    /*********************************************************************/
  1326.    /*  Process window parameters query                                  */
  1327.    /*********************************************************************/
  1328.  
  1329.    case WM_QUERYWINDOWPARAMS :
  1330.  
  1331.                        /* Get the address for the windows parameters    */
  1332.                        /* structure                                     */
  1333.  
  1334.        pwprm = (PWNDPARAMS)PVOIDFROMMP(mp1);
  1335.  
  1336.                        /* Determine the type of query                   */
  1337.  
  1338.        if ( pwprm->fsStatus & (WPM_TEXT | WPM_CCHTEXT) )
  1339.            {
  1340.                        /* Get the address of the control info from the  */
  1341.                        /* control's reserved memory                     */
  1342.  
  1343.            pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1344.  
  1345.            if ( pbc->cTitleText )
  1346.                {
  1347.                pwprm->cchText = pbc->cTitleText - 1UL;
  1348.                memcpy(pwprm->pszText, pbc->pszTitleText, pbc->cTitleText);
  1349.                }
  1350.            else
  1351.                pwprm->cchText = 0;
  1352.            }
  1353.        else
  1354.            if ( pwprm->fsStatus & WPM_TEXT )
  1355.                {
  1356.                        /* Get the address of the control info from the  */
  1357.                        /* control's reserved memory                     */
  1358.  
  1359.                pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1360.  
  1361.                        /* Copy the text from the string to the          */
  1362.                        /* structure                                     */
  1363.  
  1364.                memcpy(pwprm->pszText, pbc->pszTitleText, pbc->cTitleText);
  1365.                }
  1366.            else
  1367.                if ( pwprm->fsStatus & WPM_CCHTEXT )
  1368.                    {
  1369.                        /* Text length being asked for, get the address  */
  1370.                        /* of the text string stored in the heap         */
  1371.  
  1372.                    pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1373.  
  1374.                        /* Place the length the string within the        */
  1375.                        /* structure                                     */
  1376.  
  1377.                    if ( pbc->cTitleText )
  1378.                        pwprm->cchText = pbc->cTitleText - 1UL;
  1379.                    else
  1380.                        pwprm->cchText = 0;
  1381.                    }
  1382.                else
  1383.                    if ( pwprm->fsStatus & (WPM_CTLDATA | WPM_CBCTLDATA) )
  1384.                        {
  1385.                        for ( i = n = 0; i < pbc->cItems; i++ )
  1386.                            n += (INT)pbc->pbci[i].cLabel;
  1387.                        pwprm->cbCtlData = pbc->cHorzText + pbc->cVertText + pbc->cItems * sizeof(ULONG) +
  1388.                                           n + sizeof(BARCHARTCDATA) - 1L;
  1389.  
  1390.                        pbccd = (PBARCHARTCDATA)pwprm->pCtlData;
  1391.                        pbccd->cb = pwprm->cbCtlData;
  1392.  
  1393.                        /* Get the horizontal scale title text if        */
  1394.                        /* present                                       */
  1395.  
  1396.                        if ( (pbccd->cbHorzTitle = pbc->cHorzText) != 0UL )
  1397.                            memcpy(PSZHORZTITLE(pbccd), pbc->pszHorzText, pbccd->cbHorzTitle);
  1398.  
  1399.                        /* Get the vertical scale title text if present  */
  1400.  
  1401.                        if ( (pbccd->cbVertTitle = pbc->cVertText) != 0UL )
  1402.                            memcpy(PSZVERTTITLE(pbccd), pbc->pszVertText, pbccd->cbVertTitle);
  1403.  
  1404.                        /* Get the items of the bar chart along with the */
  1405.                        /* item labels                                   */
  1406.  
  1407.                        if ( (pbccd->cItems = pbc->cItems) != 0UL )
  1408.                            {
  1409.                            pulValues = PULONGVALUES(pbccd);
  1410.                            pb = PBYTELIST(pbccd);
  1411.                            for ( i = n = 0; i < pbccd->cItems; i++ )
  1412.                                {
  1413.                                pulValues[i] = pbc->pbci[i].ulValue;
  1414.                                memcpy(&pb[n], pbc->pbci[i].pszLabel, pbc->pbci[i].cLabel);
  1415.                                n += pbc->pbci[i].cLabel;
  1416.                                }
  1417.                            }
  1418.                        }
  1419.                    else
  1420.                        if ( pwprm->fsStatus & WPM_CTLDATA )
  1421.                            {
  1422.                            pbccd = (PBARCHARTCDATA)pwprm->pCtlData;
  1423.                            for ( i = n = 0; i < pbc->cItems; i++ )
  1424.                                n += (INT)pbc->pbci[i].cLabel;
  1425.                            pbccd->cb = pbc->cHorzText + pbc->cVertText + pbc->cItems * sizeof(ULONG) + n + sizeof(BARCHARTCDATA) - 1L;
  1426.  
  1427.                        /* Get the horizontal scale title text if        */
  1428.                        /* present                                       */
  1429.  
  1430.                            if ( (pbccd->cbHorzTitle = pbc->cHorzText) != 0UL )  
  1431.                                memcpy(PSZHORZTITLE(pbccd), pbc->pszHorzText, pbccd->cbHorzTitle);
  1432.  
  1433.                        /* Get the vertical scale title text if present  */
  1434.  
  1435.                            if ( (pbccd->cbVertTitle = pbc->cVertText) != 0UL )
  1436.                                memcpy(PSZVERTTITLE(pbccd), pbc->pszVertText, pbccd->cbVertTitle);
  1437.  
  1438.                        /* Get the items of the bar chart along with the */
  1439.                        /* item labels                                   */
  1440.  
  1441.                            if ( (pbccd->cItems = pbc->cItems) != 0UL )
  1442.                                {
  1443.                                pulValues = PULONGVALUES(pbccd);
  1444.                                pb = PBYTELIST(pbccd);
  1445.                                for ( i = n = 0; i < pbccd->cItems; i++ )
  1446.                                    {
  1447.                                    pulValues[i] = pbc->pbci[i].ulValue;
  1448.                                    memcpy(&pb[n], pbc->pbci[i].pszLabel, pbc->pbci[i].cLabel);
  1449.                                    n += pbc->pbci[i].cLabel;
  1450.                                    }
  1451.                                }
  1452.                            }
  1453.                        else
  1454.                            if ( pwprm->fsStatus & WPM_CBCTLDATA )
  1455.                                {        
  1456.                                for ( i = n = 0; i < pbc->cItems; i++ )
  1457.                                    n += (INT)pbc->pbci[i].cLabel;
  1458.                                pwprm->cbCtlData = pbc->cHorzText + pbc->cVertText + pbc->cItems * sizeof(ULONG) +
  1459.                                                   n + sizeof(BARCHARTCDATA) - 1L;
  1460.                                }
  1461.                            else
  1462.                                return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  1463.        return(MRFROMLONG(TRUE));
  1464.  
  1465.    /*********************************************************************/
  1466.    /*  Presentation parameters changed, record the changes              */
  1467.    /*********************************************************************/
  1468.  
  1469.    case WM_PRESPARAMCHANGED :
  1470.  
  1471.                        /* Get the address of the control info from the  */
  1472.                        /* control's reserved memory                     */
  1473.  
  1474.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1475.  
  1476.                        /* Get the new presentation parameter colour for */
  1477.                        /* the presentation parameter that has changed.  */
  1478.                        /* Get the colour as a RGB value so as to be     */
  1479.                        /* able to get an exact value and not an         */
  1480.                        /* approximation which could happen if the       */
  1481.                        /* presentation parameter was set as a RGB but   */
  1482.                        /* queried as an index.  When WinQueryPresParam  */
  1483.                        /* returns a 0, it indicates that no             */
  1484.                        /* presentation parameter set and the default    */
  1485.                        /* colours should be used.                       */
  1486.  
  1487.        switch ( LONGFROMMP(mp1) )
  1488.            {
  1489.            case 0 :
  1490.                pbc->lClrText       = lGetPresParam(hWnd, PP_FOREGROUNDCOLOR, PP_FOREGROUNDCOLORINDEX, SYSCLR_OUTPUTTEXT);
  1491.                pbc->lClrBackground = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR, PP_BACKGROUNDCOLORINDEX, SYSCLR_DIALOGBACKGROUND);
  1492.                pbc->lClrBorder     = lGetPresParam(hWnd, PP_BORDERCOLOR,     PP_BORDERCOLORINDEX,     SYSCLR_BUTTONDARK);
  1493.                break;
  1494.  
  1495.            case PP_FOREGROUNDCOLOR :
  1496.            case PP_FOREGROUNDCOLORINDEX :
  1497.                pbc->lClrText = lGetPresParam(hWnd, PP_FOREGROUNDCOLOR, PP_FOREGROUNDCOLORINDEX, SYSCLR_OUTPUTTEXT);
  1498.                break;
  1499.  
  1500.            case PP_BACKGROUNDCOLOR :
  1501.            case PP_BACKGROUNDCOLORINDEX :
  1502.                pbc->lClrBackground = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR, PP_BACKGROUNDCOLORINDEX, SYSCLR_DIALOGBACKGROUND);
  1503.                break;
  1504.  
  1505.            case PP_BORDERCOLOR :
  1506.            case PP_BORDERCOLORINDEX :
  1507.                pbc->lClrBorder = lGetPresParam(hWnd, PP_BORDERCOLOR, PP_BORDERCOLORINDEX, SYSCLR_BUTTONDARK);
  1508.                break;
  1509.  
  1510.            default :
  1511.                return(0L);
  1512.            }
  1513.        if ( pbc->fDraw )
  1514.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1515.        break;
  1516.  
  1517.    /*********************************************************************/
  1518.    /*  System colours changed, record the changes                       */
  1519.    /*********************************************************************/
  1520.  
  1521.    case WM_SYSCOLORCHANGE :
  1522.  
  1523.                        /* Get the address of the control info from the  */
  1524.                        /* control's reserved memory                     */
  1525.  
  1526.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1527.        pbc->lClrText       = lGetPresParam(hWnd, PP_FOREGROUNDCOLOR, PP_FOREGROUNDCOLORINDEX, SYSCLR_OUTPUTTEXT);
  1528.        pbc->lClrBackground = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR, PP_BACKGROUNDCOLORINDEX, SYSCLR_DIALOGBACKGROUND);
  1529.        pbc->lClrBorder     = lGetPresParam(hWnd, PP_BORDERCOLOR,     PP_BORDERCOLORINDEX,     SYSCLR_BUTTONDARK);
  1530.        if ( pbc->fDraw )
  1531.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1532.        break;
  1533.  
  1534. /************************************************************************/
  1535. /************************************************************************/
  1536. /*                                                                      */
  1537. /* Part 5: Mouse interface                                              */
  1538. /*                                                                      */
  1539. /************************************************************************/
  1540. /************************************************************************/
  1541.  
  1542.    /*********************************************************************/
  1543.    /*  Hit test request                                                 */
  1544.    /*********************************************************************/
  1545.  
  1546.    case WM_HITTEST :
  1547.                        /* Mouse being passed over the control, imply    */
  1548.                        /* that the control is transparent to the        */
  1549.                        /* system                                        */
  1550.  
  1551.        return(MRFROMLONG(HT_TRANSPARENT));
  1552.  
  1553. /************************************************************************/
  1554. /************************************************************************/
  1555. /*                                                                      */
  1556. /* Part 6: Keyboard interface                                           */
  1557. /*                                                                      */
  1558. /************************************************************************/
  1559. /************************************************************************/
  1560.  
  1561. /************************************************************************/
  1562. /************************************************************************/
  1563. /*                                                                      */
  1564. /* Part 7: Control Message interface                                    */
  1565. /*                                                                      */
  1566. /************************************************************************/
  1567. /************************************************************************/
  1568.  
  1569.    case BCM_SETVERTSCALETITLE :
  1570.  
  1571.                        /* Get the address of the bar chart data from    */
  1572.                        /* the control's reserved memory                 */
  1573.  
  1574.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1575.  
  1576.        if (  pbc->cVertText )
  1577.            {
  1578.            free(pbc->pszVertText);
  1579.            pbc->cVertText = 0UL;
  1580.            }
  1581.                        /* Get the horizontal scale title text if        */
  1582.                        /* present                                       */
  1583.  
  1584.        if ( (pbc->cVertText = strlen((PSZ)PVOIDFROMMP(mp1))) != 0UL )
  1585.            {
  1586.            ++pbc->cVertText;
  1587.            memcpy(pbc->pszVertText = (PSZ)malloc(pbc->cVertText), (PSZ)PVOIDFROMMP(mp1), pbc->cVertText);
  1588.            }
  1589.        if ( pbc->fDraw )
  1590.            WinInvalidateRect(hWnd, &pbc->rclVertText, FALSE);
  1591.        break;
  1592.  
  1593.    case BCM_SETHORZSCALETITLE :
  1594.  
  1595.                        /* Get the address of the bar chart data from    */
  1596.                        /* the control's reserved memory                 */
  1597.  
  1598.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1599.  
  1600.        if (  pbc->cHorzText )
  1601.            {
  1602.            free(pbc->pszHorzText);
  1603.            pbc->cHorzText = 0UL;
  1604.            }
  1605.                        /* Get the horizontal scale title text if        */
  1606.                        /* present                                       */
  1607.  
  1608.        if ( (pbc->cHorzText = strlen((PSZ)PVOIDFROMMP(mp1))) != 0UL )
  1609.            {
  1610.            ++pbc->cHorzText;
  1611.            memcpy(pbc->pszHorzText = (PSZ)malloc(pbc->cHorzText), (PSZ)PVOIDFROMMP(mp1), pbc->cHorzText);
  1612.            }
  1613.        if ( pbc->fDraw )
  1614.            WinInvalidateRect(hWnd, &pbc->rclHorzText, FALSE);
  1615.        break;
  1616.  
  1617.    case BCM_SETHORZSCALE :
  1618.  
  1619.                        /* Get the address of the bar chart data from    */
  1620.                        /* the control's reserved memory                 */
  1621.  
  1622.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1623.  
  1624.                        /* Get the items of the bar chart along with the */
  1625.                        /* item labels                                   */
  1626.  
  1627.        if ( LONGFROMMP(mp1) == pbc->cItems )
  1628.            if ( pbc->cItems )
  1629.                pbc->pbci = (PBARCHARTITEM)realloc(pbc->pbci, (pbc->cItems = LONGFROMMP(mp1)) * sizeof(BARCHARTITEM));
  1630.            else
  1631.                pbc->pbci = (PBARCHARTITEM)malloc((pbc->cItems = LONGFROMMP(mp1)) * sizeof(BARCHARTITEM));
  1632.        pb = (PBYTE)PVOIDFROMMP(mp2);
  1633.        for ( i = n = 0; i < pbc->cItems; i++ )
  1634.            {
  1635.            if ( pbc->pbci[i].cLabel )
  1636.                pbc->pbci[i].pszLabel = (PSZ)realloc(pbc->pbci[i].pszLabel, pbc->pbci[i].cLabel = strlen(&pb[n]) + 1);
  1637.            else
  1638.                pbc->pbci[i].pszLabel = (PSZ)malloc(pbc->pbci[i].cLabel = strlen(&pb[n]) + 1);
  1639.            memcpy(pbc->pbci[i].pszLabel, &pb[n], pbc->pbci[i].cLabel);
  1640.            n += pbc->pbci[i].cLabel;
  1641.            }
  1642.        if ( pbc->fDraw )
  1643.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1644.        break;
  1645.  
  1646.    case BCM_SETVALUES :
  1647.  
  1648.                        /* Get the address of the bar chart data from    */
  1649.                        /* the control's reserved memory                 */
  1650.  
  1651.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1652.        if ( LONGFROMMP(mp1) == pbc->cItems )
  1653.            if ( pbc->cItems )
  1654.                pbc->pbci = (PBARCHARTITEM)realloc(pbc->pbci, (pbc->cItems = LONGFROMMP(mp1)) * sizeof(BARCHARTITEM));
  1655.            else
  1656.                pbc->pbci = (PBARCHARTITEM)malloc((pbc->cItems = LONGFROMMP(mp1)) * sizeof(BARCHARTITEM));
  1657.        pulValues= (PULONG)PVOIDFROMMP(mp2);
  1658.        for ( i = 0; i < pbc->cItems; i++ )
  1659.            pbc->pbci[i].ulValue = pulValues[i];
  1660.        if ( pbc->fDraw )
  1661.            WinInvalidateRect(hWnd, (PRECTL)NULL, FALSE);
  1662.        break;
  1663.  
  1664. /************************************************************************/
  1665. /************************************************************************/
  1666. /*                                                                      */
  1667. /* Part 8: Painting                                                     */
  1668. /*                                                                      */
  1669. /************************************************************************/
  1670. /************************************************************************/
  1671.  
  1672.    /*********************************************************************/
  1673.    /*  Erase control background                                         */
  1674.    /*********************************************************************/
  1675.  
  1676.    case WM_ERASEBACKGROUND :
  1677.        return(MRFROMLONG(TRUE));
  1678.  
  1679.    /*********************************************************************/
  1680.    /*  Control painting                                                 */
  1681.    /*********************************************************************/
  1682.  
  1683.    case WM_PAINT :
  1684.                        /* Get the address of the bar chart data from    */
  1685.                        /* the control's reserved memory                 */
  1686.  
  1687.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1688.  
  1689.        if ( pbc->fDraw )
  1690.            {
  1691.            GpiCreateLogColorTable(hPS = WinBeginPaint(hWnd, (HPS)NULL, (PRECTL)NULL), 0L, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  1692.            WinFillRect(hPS, &pbc->rcl, CLR_WHITE);
  1693.  
  1694.            GpiSetColor(hPS, RGB_DARKGRAY);
  1695.            GpiMove(hPS, &pbc->aptl[0]);
  1696.            GpiPolyLine(hPS, 2L, &pbc->aptl[1]);
  1697.  
  1698.            GpiSetColor(hPS, RGB_WHITE);
  1699.            GpiMove(hPS, &pbc->aptl[2]);
  1700.            GpiPolyLine(hPS, 2L, &pbc->aptl[3]);
  1701.  
  1702.            GpiSetColor(hPS, RGB_PALEGRAY);
  1703.            GpiMove(hPS, &pbc->aptl[7]);
  1704.            GpiPolyLine(hPS, 2L, &pbc->aptl[8]);
  1705.  
  1706.            GpiSetColor(hPS, RGB_BLACK);
  1707.            GpiMove(hPS, &pbc->aptl[5]);
  1708.            GpiPolyLine(hPS, 2L, &pbc->aptl[6]);
  1709.  
  1710.            if ( pbc->cTitleText )
  1711.                WinDrawText(hPS, pbc->cTitleText, pbc->pszTitleText, &pbc->rclTitleText, pbc->lClrText, pbc->lClrBackground,
  1712.                            DT_VCENTER | DT_CENTER | DT_ERASERECT);
  1713.  
  1714.            if ( pbc->cHorzText )
  1715.                WinDrawText(hPS, pbc->cHorzText, pbc->pszHorzText, &pbc->rclHorzText, pbc->lClrText, pbc->lClrBackground,
  1716.                            DT_VCENTER | DT_CENTER | DT_ERASERECT);
  1717.            if ( pbc->cVertText )
  1718.                {
  1719.                GpiSetCharBox(hPS, &pbc->sizfx);
  1720.                GpiCreateLogFont(hPS, (PSTR8)NULL, 4L, &pbc->fat);
  1721.                GpiSetCharSet(hPS, 4L);
  1722.  
  1723.                GpiSetCharAngle(hPS, &gradl);
  1724.                WinDrawText(hPS, pbc->cVertText, pbc->pszVertText, &pbc->rclVertText, pbc->lClrText, pbc->lClrBackground,
  1725.                            DT_VCENTER | DT_CENTER | DT_ERASERECT);
  1726.                GpiSetCharSet(hPS, 0L);
  1727.                GpiDeleteSetId(hPS, 4L);
  1728.                }
  1729.            if ( pbc->cItems )
  1730.                for ( i = 0; i < pbc->cItems; i++ )
  1731.                    {
  1732.                    WinFillRect(hPS, &pbc->pbci[i].rcl, RGB_RED);
  1733.                    GpiMove(hPS, &pbc->pbci[i].aptl[3]);
  1734.                    GpiPolyLine(hPS, 4L, pbc->pbci[i].aptl);
  1735.                    WinDrawText(hPS, pbc->pbci[i].cLabel, pbc->pbci[i].pszLabel, &pbc->pbci[i].rclLabel, pbc->lClrText, pbc->lClrBackground,
  1736.                                DT_VCENTER | DT_CENTER | DT_ERASERECT);
  1737.                    }
  1738.            if ( pbc->cScales )
  1739.                for ( i = 0; i < pbc->cScales; i++ )
  1740.                    WinDrawText(hPS, pbc->psi[i].cLabel, pbc->psi[i].pszLabel, &pbc->psi[i].rcl, pbc->lClrText, pbc->lClrBackground,
  1741.                                DT_VCENTER | DT_CENTER | DT_ERASERECT);
  1742.            WinEndPaint(hPS);
  1743.            }
  1744.        else
  1745.            WinEndPaint(WinBeginPaint(hWnd, (HPS)NULL, (PRECTL)NULL));
  1746.        break;
  1747.  
  1748. /************************************************************************/
  1749. /************************************************************************/
  1750. /*                                                                      */
  1751. /* Part 9: Control being destroyed                                      */
  1752. /*                                                                      */
  1753. /************************************************************************/
  1754. /************************************************************************/
  1755.  
  1756.    /*********************************************************************/
  1757.    /*  Control being destroy, perform necessary cleanup                 */
  1758.    /*********************************************************************/
  1759.  
  1760.    case WM_DESTROY :
  1761.                        /* Get the address of the bar chart data from    */
  1762.                        /* the control's reserved memory                 */
  1763.  
  1764.        pbc = (PBARCHART)WinQueryWindowPtr(hWnd, QWW_CDATA);
  1765.  
  1766.        if ( pbc->cTitleText )
  1767.            free(pbc->pszTitleText);
  1768.        if ( pbc->cHorzText )
  1769.            free(pbc->pszHorzText);
  1770.  
  1771.        if ( pbc->cVertText )
  1772.            free(pbc->pszVertText);
  1773.        if ( pbc->cScales )
  1774.            {
  1775.            for ( i = 0; i < pbc->cScales; i++ )
  1776.                free(pbc->psi[i].pszLabel);
  1777.            free(pbc->psi);
  1778.            }
  1779.        if ( pbc->cItems )
  1780.            free(pbc->pbci);
  1781.        free(pbc);
  1782.        break;
  1783.                        /* Default message processing                    */
  1784.    default :
  1785.        return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  1786.    }
  1787.  
  1788. return(0L);
  1789. }
  1790.