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