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