home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / OS2DCTRL.ZIP / IMAGEBTN.C < prev    next >
C/C++ Source or Header  |  1993-01-27  |  75KB  |  2,082 lines

  1.  
  2. /* Program name:   ImageBtn.C  Title: Demystifying Custom Controls    */
  3. /* OS/2    Developer Magazine, Issue:  Winter '93, page 120                */
  4. /* Author:  Mark Benge     Phone:    (919) 469-6446 Fax: (919) 469-6025    */
  5. /*        Matt Smith     Phone:    (416) 363-2292 Fax: (416) 363-8452    */
  6. /* Description:     Custom    controls demystified.  Sample image button    */
  7. /*         with text.  Can be used as the    basis for other        */
  8. /*         custom    controls.                    */
  9. /* Program Requirements:  OS/2 2.0, IBM    C Set/2    or WATCOM C 386/9.0    */
  10. /*              OS/2 Toolkit                    */
  11.  
  12. /* DISCLAIMER OF WARRANTIES:                        */
  13. /* -------------------------                        */
  14. /* The following [enclosed] code is sample code    created    by IBM        */
  15. /* Corporation and Prominare Inc.  This    sample code is not part    of any    */
  16. /* standard IBM    product    and is provided    to you solely for the purpose    */
  17. /* of assisting    you in the development of your applications.  The code    */
  18. /* is provided "AS IS",    without    warranty of any    kind.  Neither IBM nor    */
  19. /* Prominare shall be liable for any damages arising out of your    */
  20. /* use of the sample code, even    if they    have been advised of the    */
  21. /* possibility of such damages.                        */
  22.  
  23. #define    INCL_DOS           /* Include OS/2 DOS Kernal        */
  24. #define    INCL_GPI           /* Include OS/2 PM GPI Interface    */
  25. #define    INCL_WIN           /* Include OS/2 PM Windows Interface    */
  26.  
  27. #include <os2.h>
  28. #include <string.h>
  29.  
  30. #include "imagebtn.h"
  31.  
  32. /* This    module contains    an example installable control that can    be used    */
  33. /* by any OS/2 2.0 Presentation    Manager    application.  The control    */
  34. /* demonstrates    the principles of creating a custom control such    */
  35. /* that    new custom controls can    be created using this as a model.    */
  36. /*                                    */
  37. /* The control can be compiled using the IBM C Set/2 Version 1.0 with    */
  38. /* the following:                            */
  39. /*                                    */
  40. /*   Icc -G3e- -O+ -Rn -W3 -C -FoImageBtn.Obj ImageBtn.C        */
  41. /*                                    */
  42. /* The control can be compiled using the WATCOM    C 386 Version 9.0 with    */
  43. /* the following:                            */
  44. /*                                    */
  45. /*   Wcl386 -ms    -3s -bd    -s -ox -zp4 -w3    -c -fo=ImageBtn.Obj ImageBtn.C    */
  46.  
  47. /* Filename:   ImageBtn.C                        */
  48.  
  49. /*  Version:   1.00                            */
  50. /*  Created:   1992-06-02                        */
  51. /*  Revised:   1992-08-30                        */
  52. /* Released:   1993-01-27                        */
  53.  
  54. /* Routines:   static VOID CalcImagePos(PIMGBTN    pimgbtn, PRECTL    prcl,    */
  55. /*                    PPOINTL    pptl, LONG cx, LONG cy,    */
  56. /*                    LONG xShift, LONG yShift);    */
  57. /*           static VOID SizeButton(HWND hWnd, LONG x, LONG y,    */
  58. /*                      LONG cx, LONG cy);        */
  59. /*           static VOID LoadBitmaps(PIMAGEBUTTON pib,        */
  60. /*                       PIMGBTN pimgbtn,    HMODULE    hmod);    */
  61. /*           static LONG lGetPresParam(HWND hWnd, ULONG ulID1,    */
  62. /*                     ULONG ulID2, LONG lDefault);    */
  63. /*           static VOID SetDefaultColours(HWND hWnd,            */
  64. /*                         PIMGBTN pimgbtn);        */
  65. /*           MRESULT EXPENTRY    ImageBtnWndProc(HWND hWnd, ULONG msg,    */
  66. /*                        MPARAM mp1, MPARAM mp2);*/
  67.  
  68.  
  69. /* Copyright ╕ International Business Machines Corp., 1991,1992,1993.    */
  70. /* Copyright ╕ 1989-1993  Prominare Inc.  All Rights Reserved.        */
  71.  
  72. /* --------------------------------------------------------------------    */
  73.  
  74.  
  75. /* --- Internal    Structures --------------------------------------------    */
  76.  
  77. typedef    struct _IMGBTN           /* imgbtn */
  78.    {
  79.    ULONG    id;               /* ID Value                */
  80.    ULONG    flStyle;           /* Style                */
  81.    BOOL        fFocus;           /* Focus Flag            */
  82.    RECTL    rclText;           /* Text Limits Rectangle        */
  83.    RECTL    rcl;           /* Frame Rectangle            */
  84.    RECTL    rclHitTest;           /* Hit Test Rectangle        */
  85.    RECTL    rclSrc;           /* Source Rectangle    - Up        */
  86.    RECTL    rclSrcDown;           /* Source Rectangle    - Down        */
  87.    RECTL    rclSrcDisabled;       /* Source Rectangle    - Disabled    */
  88.    POINTL   ptlDest;           /* Destination Point    - Up        */
  89.    POINTL   ptlDestDown;       /* Destination Point    - Down        */
  90.    POINTL   ptlDestDisabled;       /* Destination Point    - Disabled    */
  91.    HBITMAP  hbm;           /* Bitmap Handle            */
  92.    HBITMAP  hbmDown;           /* Bitmap Handle            */
  93.    HBITMAP  hbmDisabled;       /* Bitmap Handle            */
  94.    POINTL   aptlFocus[5];       /* Focus Emphasis Polyline Array    */
  95.    POINTL   aptlOutline[8];       /* Outline Polyline Array        */
  96.    POINTL   aptlShadow[12];       /* Shadow Polyline Array        */
  97.    HWND        hwndOwner;           /* Owner Window Handle        */
  98.    HWND        hwndParent;           /* Parent Window Handle        */
  99.    ULONG    flState;           /* Button State            */
  100.    ULONG    cx;               /* Bitmap Width  - Up        */
  101.    ULONG    cy;               /* Bitmap Height - Up        */
  102.    ULONG    cxDown;           /* Bitmap Width  - Down        */
  103.    ULONG    cyDown;           /* Bitmap Height - Down        */
  104.    ULONG    cxDisabled;           /* Bitmap Width  - Disabled        */
  105.    ULONG    cyDisabled;           /* Bitmap Height - Disabled        */
  106.    HPOINTER hptrArrow;           /* Arrow Pointer            */
  107.    CHAR        szText[256];       /* Button Text            */
  108.    ULONG    aClr[7];           /* Presentation Colours Array    */
  109.    ULONG    lButtonShadow;       /* Button Shadow Colour        */
  110.    ULONG    lButtonFace;       /* Button Face Colour        */
  111.    ULONG    lButtonReflect;       /* Button Reflection    Edge Colour    */
  112.    } IMGBTN ;
  113.  
  114. typedef    IMGBTN *PIMGBTN;
  115.  
  116. /* --- CTLDATA Structure Definition -----------------------------------    */
  117.  
  118. /************************************************************************/
  119. /*                                    */
  120. /*     NOTE:   ID's for the bitmaps must be 0 < id < 65535              */
  121. /*           This limitation is due to OS/2 PM Version 2.0        */
  122. /*                                    */
  123. /*           OS/2 2.0    requires the first element of the CTLDATA    */
  124. /*           structure to be the size    of the structure and this    */
  125. /*           value must be less than 64 KB                */
  126. /*                                    */
  127. /************************************************************************/
  128.  
  129. typedef    struct _IMAGEBUTTON       /* ibtn */
  130.    {                   /* Size:  16    Bytes            */
  131.    LONG    cb;               /* Structure    Size            */
  132.    LONG    idBitmap;           /* Bitmap ID    : Normal or Up Position    */
  133.    LONG    idBitmapDown;           /* Bitmap ID    : Down Position        */
  134.    LONG    idBitmapDisabled;       /* Bitmap ID    : Disabled        */
  135.    } IMAGEBUTTON ;
  136.  
  137. typedef    IMAGEBUTTON *PIMAGEBUTTON;
  138.  
  139. /* --- Module Prototype    Definitions -----------------------------------    */
  140.  
  141. static VOID CalcImagePos(PIMGBTN pimgbtn, PRECTL prcl, PPOINTL pptl, LONG cx, LONG cy, LONG xShift, LONG yShift);
  142. static VOID SizeButton(HWND hWnd, LONG x, LONG y, LONG cx, LONG    cy);
  143. static VOID LoadBitmaps(PIMAGEBUTTON pib, PIMGBTN pimgbtn, HMODULE hmod);
  144. static LONG lGetPresParam(HWND hWnd, ULONG ulID1, ULONG    ulID2, LONG lDefault);
  145. static VOID SetDefaultColours(HWND hWnd, PIMGBTN pimgbtn);
  146.  
  147. MRESULT    EXPENTRY ImageBtnWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  148.  
  149. static HMODULE hmodDLL;           /* DLL Module Handle            */
  150.  
  151. #ifdef __IBMC__
  152.  
  153. #pragma    subtitle("   Image Button Control - DLL Initialization/Termination Procedure")
  154. #pragma    page( )
  155.  
  156. /* --- _Dll_InitTerm ----------------------------------- [ Public ] ---    */
  157. /*                                    */
  158. /*     This function is    used to    provide    the DLL    initialization and    */
  159. /*     termination.  The function is called by the C startup code    */
  160. /*     and allows the control to register itself and provide any    */
  161. /*     necessary startup.                        */
  162. /*                                    */
  163. /*     This function is    designed for IBM C Set/2 Version 1.0        */
  164. /*                                    */
  165. /*     Upon Entry:                            */
  166. /*                                    */
  167. /*     ULONG hModule; =    DLL Module Handle                */
  168. /*     ULONG fl;      =    Startup    / Termination Flag            */
  169. /*                                    */
  170. /*     Upon Exit:                            */
  171. /*                                    */
  172. /*     _Dll_InitTerm =    0 : Error Return                */
  173. /*             =    1 : Successful Startup / Termination        */
  174. /*                                    */
  175. /* --------------------------------------------------------------------    */
  176.  
  177. ULONG _System _Dll_InitTerm(ULONG hModule, ULONG fl)
  178.  
  179. {
  180.                /* Determine if in startup or termination mode    */
  181. if ( fl    == 0 )
  182.                /* DLL being initialized, save the DLL module    */
  183.                /* handle to allow the bitmap loading routines    */
  184.                /* routines a means of loading the default    */
  185.                /* bitmaps when required                */
  186.    hmodDLL = hModule;
  187.  
  188. return(1UL);
  189. }
  190.  
  191. #else
  192.  
  193. extern INT __hmodule;
  194.  
  195. #pragma    subtitle("   Image Button Control - DLL Initialization Procedure")
  196. #pragma    page( )
  197.  
  198. /* --- __dll_initialize    -------------------------------- [ Public ] ---    */
  199. /*                                    */
  200. /*     This function is    used to    provide    the DLL    initialization and    */
  201. /*     termination.  The function is called by the C startup code    */
  202. /*     and allows the control to register itself and provide any    */
  203. /*     necessary startup.                        */
  204. /*                                    */
  205. /*     This function is    designed for WATCOM C 386 Version 9.0        */
  206. /*                                    */
  207. /*     Upon Entry:                            */
  208. /*                                    */
  209. /*     Nothing                                */
  210. /*                                    */
  211. /*     Upon Exit:                            */
  212. /*                                    */
  213. /*     __dll_initialize    =  0 : Error Return                */
  214. /*            =  1 : Successful Startup            */
  215. /*                                    */
  216. /* --------------------------------------------------------------------    */
  217.  
  218. INT __dll_initialize(VOID)
  219.  
  220. {
  221.                /* DLL being initialized, save the DLL module    */
  222.                /* handle to allow the bitmap loading routines    */
  223.                /* routines a means of loading the default    */
  224.                /* bitmaps when required                */
  225. hmodDLL    = __hmodule;
  226.  
  227. return(1);
  228. }
  229. #pragma    subtitle("   Image Button Control - DLL Initialization Procedure")
  230. #pragma    page( )
  231.  
  232. /* --- __dll_terminate --------------------------------- [ Public ] ---    */
  233. /*                                    */
  234. /*     This function is    used to    provide    the DLL    initialization and    */
  235. /*     termination.  The function is called by the C startup code    */
  236. /*     and allows the control to register itself and provide any    */
  237. /*     necessary startup.                        */
  238. /*                                    */
  239. /*     This function is    designed for WATCOM C 386 Version 9.0        */
  240. /*                                    */
  241. /*     Upon Entry:                            */
  242. /*                                    */
  243. /*     Nothing                                */
  244. /*                                    */
  245. /*     Upon Exit:                            */
  246. /*                                    */
  247. /*     __dll_terminate =  0 : Error Return                */
  248. /*               =  1 : Successful Startup            */
  249. /*                                    */
  250. /* --------------------------------------------------------------------    */
  251.  
  252. INT __dll_terminate(VOID)
  253.  
  254. {
  255.  
  256. return(1);
  257.  
  258. }
  259.  
  260. #endif
  261.  
  262. #pragma    subtitle("   Image Button Control - Image Positioning Procedure")
  263. #pragma    page( )
  264.  
  265. /* --- CalcImagePos -----------------------------------    [ Private ] ---    */
  266. /*                                    */
  267. /*     This function is    used to    calculate the bitmap display        */
  268. /*     co-ordinates such that the image    is properly placed within    */
  269. /*     the display area.  It may be necessary to clip the image    to    */
  270. /*     fit the button area if the image    is too large for the width    */
  271. /*     or the height.                            */
  272. /*                                    */
  273. /*     Upon Entry:                            */
  274. /*                                    */
  275. /*     PIMGBTN pimgbtn;    = Image    Button Structure Pointer        */
  276. /*     PRECTL  prcl;    = Source Rectangle Pointer            */
  277. /*     POINTL  pptl;    = Target Display Point Pointer            */
  278. /*     LONG    cx;    = Button Width                    */
  279. /*     LONG    cy;    = Button Height                    */
  280. /*     LONG    xShift;    = x Shift for Down Press            */
  281. /*     LONG    yShift;    = y Shift for Down Press            */
  282. /*                                    */
  283. /*     Upon Exit:                            */
  284. /*                                    */
  285. /*     Nothing                                */
  286. /*                                    */
  287. /* --------------------------------------------------------------------    */
  288.  
  289. static VOID CalcImagePos(PIMGBTN pimgbtn, PRECTL prcl, PPOINTL pptl,
  290.              LONG cx, LONG cy, LONG    xShift,    LONG yShift)
  291.  
  292. {
  293.                /* Determine if the bitmap image    width is    */
  294.                /* smaller than the button width    and if the case    */
  295.                /* determine the    best way of centering the image    */
  296.                /* horizontally within the button rectangle    */
  297.  
  298. if ( (pimgbtn->rcl.xRight - pimgbtn->rcl.xLeft)    < cx )
  299.    {
  300.    prcl->xRight    = (prcl->xLeft = (cx -
  301.           (pimgbtn->rcl.xRight - pimgbtn->rcl.xLeft)) /    2L) +
  302.           (pimgbtn->rcl.xRight - pimgbtn->rcl.xLeft) - xShift;
  303.    pptl->x = 0L    + xShift;
  304.    }
  305. else
  306.    {
  307.    pptl->x = (pimgbtn->rcl.xRight - pimgbtn->rcl.xLeft - cx) / 2L + 1L + xShift;
  308.    prcl->xLeft    = 0;
  309.    prcl->xRight    = cx - xShift;
  310.    }
  311.                /* Determine if the bitmap image    height is    */
  312.                /* smaller than the button height and if    the    */
  313.                /* case determine the best way of centering the    */
  314.                /* image    vertically within the button rectangle    */
  315.  
  316. if ( ((pimgbtn->rcl.yTop - pimgbtn->rcl.yBottom) - (pimgbtn->rclText.yTop + 2L)) < cy )
  317.    {
  318.    prcl->yBottom = (cy - ((pimgbtn->rcl.yTop - pimgbtn->rcl.yBottom) -
  319.               (pimgbtn->rclText.yTop + 2L))) /2L;
  320.    prcl->yTop =    prcl->yBottom +
  321.         ((pimgbtn->rcl.yTop - pimgbtn->rcl.yBottom) -
  322.          (pimgbtn->rclText.yTop    + 2L));
  323.    pptl->y = pimgbtn->rclText.yTop + 2L;
  324.    }
  325. else
  326.    {
  327.    pptl->y = pimgbtn->rclText.yTop + 2L;
  328.    prcl->yBottom = 0;
  329.    prcl->yTop     = cy;
  330.    }
  331.                /* Check    to see if the image should be shifted    */
  332.                /* which    is usually done    for the    image when the    */
  333.                /* button is pressed.  The shifting of the image    */
  334.                /* gives    a greater 3D impression    of movement.    */
  335. if ( yShift )
  336.    prcl->yBottom += yShift;
  337. }
  338. #pragma    subtitle("   Image Button Control - Control Sizing Procedure")
  339. #pragma    page( )
  340.  
  341. /* --- SizeButton -------------------------------------    [ Private ] ---    */
  342. /*                                    */
  343. /*     This function is    used to    calculate various elements of that    */
  344. /*     make up the button.                        */
  345. /*                                    */
  346. /*     Upon Entry:                            */
  347. /*                                    */
  348. /*     HWND hWnd; = Window Handle                    */
  349. /*     LONG x;      = x Starting Point                    */
  350. /*     LONG y;      = y Starting Point                    */
  351. /*     LONG cx;      = Button Width                    */
  352. /*     LONG cy;      = Button Height                    */
  353. /*                                    */
  354. /*     Upon Exit:                            */
  355. /*                                    */
  356. /*     Nothing                                */
  357. /*                                    */
  358. /* --------------------------------------------------------------------    */
  359.  
  360. static VOID SizeButton(HWND hWnd, LONG x, LONG y, LONG cx, LONG    cy)
  361.  
  362. {
  363. HPS    hPS;               /* Presentation Space Handle        */
  364. PIMGBTN    pimgbtn;           /* Image Button Structure Pointer    */
  365. LONG    yStart;               /* Button Start Co-ordinate        */
  366.  
  367.                /* Get the address of the private control data    */
  368.                /* structure                    */
  369.  
  370. pimgbtn    = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  371.  
  372.                /* Save the bounding rectangle of the control    */
  373.  
  374. pimgbtn->rcl.xRight  = (pimgbtn->rcl.xLeft   = x) + cx;
  375. pimgbtn->rcl.yTop    = (pimgbtn->rcl.yBottom = y) + cy;
  376.  
  377.                /* Set the display area for the text of the    */
  378.                /* control                    */
  379.  
  380. pimgbtn->rclText = pimgbtn->rcl;
  381. pimgbtn->rclText.xLeft    += 2L;
  382. pimgbtn->rclText.xRight    -= 2L;
  383. pimgbtn->rclText.yBottom = 4L;
  384.  
  385.                /* Determine the    positioning of the text    by    */
  386.                /* finding its drawing rectangle            */
  387.  
  388. WinDrawText(hPS    = WinGetPS(hWnd), -1, pimgbtn->szText, &pimgbtn->rclText,
  389.         SYSCLR_OUTPUTTEXT, SYSCLR_BACKGROUND,
  390.         DT_MNEMONIC    | DT_CENTER | DT_BOTTOM    | DT_QUERYEXTENT);
  391.  
  392. WinReleasePS(hPS);
  393.                /* Calculate the    focus emphasis polyline    array    */
  394.                /* points.  They    are as follows:            */
  395.                /*                        */
  396.                /*      1       2                */
  397.                /*       +------+                */
  398.                /*       | Text |                */
  399.                /*     0 +------+                */
  400.                /*       4       3                */
  401.                /*                        */
  402.                /* The emphasis array is    based on the actual    */
  403.                /* display rectangle of the text.        */
  404.  
  405. pimgbtn->aptlFocus[0].x    = pimgbtn->rclText.xLeft   - 1L;
  406. pimgbtn->aptlFocus[0].y    = pimgbtn->rclText.yBottom - 1L;
  407. pimgbtn->aptlFocus[1].x    = pimgbtn->rclText.xLeft   - 1L;
  408. pimgbtn->aptlFocus[1].y    = pimgbtn->rclText.yTop       + 1L;
  409. pimgbtn->aptlFocus[2].x    = pimgbtn->rclText.xRight  + 1L;
  410. pimgbtn->aptlFocus[2].y    = pimgbtn->rclText.yTop       + 1L;
  411. pimgbtn->aptlFocus[3].x    = pimgbtn->rclText.xRight  + 1L;
  412. pimgbtn->aptlFocus[3].y    = pimgbtn->rclText.yBottom - 1L;
  413. pimgbtn->aptlFocus[4].x    = pimgbtn->rclText.xLeft   - 1L;
  414. pimgbtn->aptlFocus[4].y    = pimgbtn->rclText.yBottom - 1L;
  415.  
  416.                /* Save the bounding rectangle of the control    */
  417.  
  418. pimgbtn->rcl.xRight  = (pimgbtn->rcl.xLeft   = x) + cx;
  419. pimgbtn->rcl.yTop    = (pimgbtn->rcl.yBottom = y) + cy;
  420.  
  421. pimgbtn->rclHitTest = pimgbtn->rcl;
  422.  
  423.                /* Set the starting point for the button    image    */
  424.                /* based    on its style in    relation to the    text    */
  425.                /* that is to be    displayed for the control    */
  426.  
  427. if ( pimgbtn->flStyle &    IS_TEXTONBTN )
  428.    pimgbtn->rclHitTest.yBottom = yStart    = 0L;
  429. else
  430.    pimgbtn->rclHitTest.yBottom = yStart    = pimgbtn->rclText.yTop    + 2L;
  431.  
  432.                /* Calculate the    control    outline    polyline array    */
  433.                /* points.  They    are as follows:            */
  434.                /*                        */
  435.                /*       2      3                */
  436.                /*     1 +------+ 4                */
  437.                /*       |      |                */
  438.                /*     0 +------+ 5                */
  439.                /*       7      6                */
  440.  
  441. pimgbtn->aptlOutline[0].x = 0L;
  442. pimgbtn->aptlOutline[0].y = yStart + 1L;
  443. pimgbtn->aptlOutline[1].x = 0L;
  444. pimgbtn->aptlOutline[1].y = pimgbtn->rcl.yTop -    1L;
  445. pimgbtn->aptlOutline[2].x = 1L;
  446. pimgbtn->aptlOutline[2].y = pimgbtn->rcl.yTop;
  447. pimgbtn->aptlOutline[3].x = pimgbtn->rcl.xRight    - 1L;
  448. pimgbtn->aptlOutline[3].y = pimgbtn->rcl.yTop;
  449. pimgbtn->aptlOutline[4].x = pimgbtn->rcl.xRight;
  450. pimgbtn->aptlOutline[4].y = pimgbtn->rcl.yTop -    1L;
  451. pimgbtn->aptlOutline[5].x = pimgbtn->rcl.xRight;
  452. pimgbtn->aptlOutline[5].y = yStart + 1L;
  453. pimgbtn->aptlOutline[6].x = pimgbtn->rcl.xRight    - 1L;
  454. pimgbtn->aptlOutline[6].y = yStart;
  455. pimgbtn->aptlOutline[7].x = 1L;
  456. pimgbtn->aptlOutline[7].y = yStart;
  457.  
  458.                /* Set the starting point for the button    image    */
  459.                /* based    on its style in    relation to the    text    */
  460.                /* that is to be    displayed for the control    */
  461.  
  462. if ( pimgbtn->flStyle &    IS_TEXTONBTN )
  463.    yStart = 1L;
  464. else
  465.    yStart = pimgbtn->rclText.yTop + 2L;
  466.  
  467.                /* Calculate the    control    chamfer    polyline array    */
  468.                /* points.  They    are as follows:            */
  469.                /*                        */
  470.                /*      1           2            */
  471.                /*       +----------+                */
  472.                /*       |+--------+|    8            */
  473.                /*       ||4       3 ||                */
  474.                /*       ||        9||                */
  475.                /*       ||5         ||                */
  476.                /*       || 11   10||                */
  477.                /*       |+--------+|                */
  478.                /*     0 +----------+                */
  479.                /*       6           7            */
  480.  
  481. pimgbtn->aptlShadow[ 0].x = 1L;
  482. pimgbtn->aptlShadow[ 0].y = yStart;
  483. pimgbtn->aptlShadow[ 1].x = 1L;
  484. pimgbtn->aptlShadow[ 1].y = pimgbtn->rcl.yTop -    1;
  485. pimgbtn->aptlShadow[ 2].x = pimgbtn->rcl.xRight    - 1;
  486. pimgbtn->aptlShadow[ 2].y = pimgbtn->rcl.yTop -    1;
  487. pimgbtn->aptlShadow[ 3].x = pimgbtn->rcl.xRight    - 2;
  488. pimgbtn->aptlShadow[ 3].y = pimgbtn->rcl.yTop -    2;
  489. pimgbtn->aptlShadow[ 4].x = 2L;
  490. pimgbtn->aptlShadow[ 4].y = pimgbtn->rcl.yTop -    2;
  491. pimgbtn->aptlShadow[ 5].x = 2L;
  492. pimgbtn->aptlShadow[ 5].y = yStart + 1L;
  493.  
  494. pimgbtn->aptlShadow[ 6].x = 2L;
  495. pimgbtn->aptlShadow[ 6].y = yStart;
  496. pimgbtn->aptlShadow[ 7].x = pimgbtn->rcl.xRight    - 1L;
  497. pimgbtn->aptlShadow[ 7].y = yStart;
  498. pimgbtn->aptlShadow[ 8].x = pimgbtn->rcl.xRight    - 1L;
  499. pimgbtn->aptlShadow[ 8].y = pimgbtn->rcl.yTop -    2L;
  500. pimgbtn->aptlShadow[ 9].x = pimgbtn->rcl.xRight    - 2L;
  501. pimgbtn->aptlShadow[ 9].y = pimgbtn->rcl.yTop -    3L;
  502. pimgbtn->aptlShadow[10].x = pimgbtn->rcl.xRight    - 2L;
  503. pimgbtn->aptlShadow[10].y = yStart + 1L;
  504. pimgbtn->aptlShadow[11].x = 2L;
  505. pimgbtn->aptlShadow[11].y = yStart + 1L;
  506.  
  507.                /* Determine if the bitmap image    width is    */
  508.                /* smaller than the button width    and if the case    */
  509.                /* determine the    best way of centering the image    */
  510.                /* horizontally within the button rectangle    */
  511.  
  512. CalcImagePos(pimgbtn, &pimgbtn->rclSrc,    &pimgbtn->ptlDest,
  513.          pimgbtn->cx, pimgbtn->cy, 0L, 0L);
  514. CalcImagePos(pimgbtn, &pimgbtn->rclSrcDown, &pimgbtn->ptlDestDown,
  515.          pimgbtn->cxDown, pimgbtn->cyDown, 2L, 2L);
  516. CalcImagePos(pimgbtn, &pimgbtn->rclSrcDisabled,    &pimgbtn->ptlDestDisabled,
  517.          pimgbtn->cxDisabled, pimgbtn->cyDisabled, 0L, 0L);
  518. }
  519. #pragma    subtitle("   Image Button Control - Bitmap Load Procedure")
  520. #pragma    page( )
  521.  
  522. /* --- LoadBitmaps ------------------------------------    [ Private ] ---    */
  523. /*                                    */
  524. /*     This function is    used to    load the specified bitmaps from    the    */
  525. /*     resources of the    calling    executable using the information    */
  526. /*     provided    within a CTLDATA type structure.            */
  527. /*                                    */
  528. /*     Upon Entry:                            */
  529. /*                                    */
  530. /*     PIMAGEBUTTON pib;     = Image Button CTLDATA Pointer        */
  531. /*     PIMGBTN        pimgbtn; = Internal    Data Pointer            */
  532. /*     HMODULE        hmod;    = Module Handle                */
  533. /*                                    */
  534. /*     Upon Exit:                            */
  535. /*                                    */
  536. /*     Nothing                                */
  537. /*                                    */
  538. /* --------------------------------------------------------------------    */
  539.  
  540. static VOID LoadBitmaps(PIMAGEBUTTON pib, PIMGBTN pimgbtn, HMODULE hmod)
  541.  
  542. {
  543. BITMAPINFOHEADER bmpi;           /* Bitmap Information Header        */
  544. HBITMAP         hbm;           /* Bitmap Handle            */
  545. HMODULE         hmodBitmap;       /* Module Handle            */
  546. HPS         hPS;           /* Presentation Space Handle        */
  547. LONG         id;           /* ID Value                */
  548.  
  549.                /* Load each of the image bitmaps from the    */
  550.                /* calling executable and create    a bitmap that    */
  551.                /* will be shown    in each    button when the    ID for    */
  552.                /* bitmaps are provided otherwise use the    */
  553.                /* images contained within the control DLL    */
  554.  
  555. if ( pib && pib->idBitmap )
  556.    {
  557.                /* Set the module handle    for the    bitmap as the    */
  558.                /* resources within the calling executable    */
  559.    hmodBitmap =    hmod;
  560.    id          =    pib->idBitmap;
  561.    }
  562. else
  563.    {
  564.                /* Set the module handle    for the    bitmap as the    */
  565.                /* resources within DLL therefore get the    */
  566.                /* handle of the    DLL                */
  567.  
  568.    hmodBitmap =    hmodDLL;
  569.    id          =    IDB_DEFAULT;
  570.    }
  571.                /* Get a    temporary presentation space for the    */
  572.                /* control to allow the creation    of the bitmaps    */
  573.                /* for each of the buttons.  Then load the    */
  574.                /* bitmap image in from the selected executable    */
  575.                /* or DLL.  When    this fails, try    getting    the    */
  576.                /* default image    from the resources of the DLL.    */
  577.  
  578.  
  579. if ( hbm = GpiLoadBitmap(hPS = WinGetPS(HWND_DESKTOP), hmodBitmap,
  580.              id, 0L, 0L) )
  581.    {
  582.    if (    pimgbtn->hbm )
  583.        GpiDeleteBitmap(pimgbtn->hbm);
  584.    pimgbtn->hbm    = hbm;
  585.    }
  586. else
  587.    if (    hbm = GpiLoadBitmap(hPS, hmodDLL, IDB_DEFAULT, 0L, 0L) )
  588.        {
  589.        if ( pimgbtn->hbm )
  590.        GpiDeleteBitmap(pimgbtn->hbm);
  591.        pimgbtn->hbm = hbm;
  592.        }
  593.                /* Get the size of the bitmap that has been    */
  594.                /* loaded to allow the proper positioning of it    */
  595.                /* within the final button            */
  596.  
  597. GpiQueryBitmapParameters(pimgbtn->hbm, &bmpi);
  598. pimgbtn->cx = bmpi.cx;
  599. pimgbtn->cy = bmpi.cy;
  600.                /* Get the down ID of the button            */
  601.  
  602. if ( pib && pib->idBitmapDown )
  603.    id =    pib->idBitmapDown;
  604. else
  605.    id =    IDB_DEFAULTDOWN;
  606.                /* Load the down    image from the resources    */
  607.  
  608. if ( hbm = GpiLoadBitmap(hPS, hmodBitmap, id, 0L, 0L) )
  609.    {
  610.    if (    pimgbtn->hbmDown )
  611.        GpiDeleteBitmap(pimgbtn->hbmDown);
  612.    pimgbtn->hbmDown = hbm;
  613.    }
  614. else
  615.    if (    hbm = GpiLoadBitmap(hPS, hmodDLL, IDB_DEFAULTDOWN, 0L, 0L) )
  616.        {
  617.        if ( pimgbtn->hbmDown )
  618.        GpiDeleteBitmap(pimgbtn->hbmDown);
  619.        pimgbtn->hbmDown    = hbm;
  620.        }
  621.                /* Get the size of the bitmap that has been    */
  622.                /* loaded to allow the proper positioning of it    */
  623.                /* within the final button            */
  624.  
  625. GpiQueryBitmapParameters(pimgbtn->hbmDown, &bmpi);
  626. pimgbtn->cxDown    = bmpi.cx;
  627. pimgbtn->cyDown    = bmpi.cy;
  628.  
  629.                /* Get the disabled ID of the button        */
  630.  
  631. if ( pib && pib->idBitmapDisabled)
  632.    id =    pib->idBitmapDisabled;
  633. else
  634.    id =    IDB_DEFAULTDISABLED;
  635.  
  636.                /* Load the disabled image from the resources    */
  637.  
  638. if ( hbm = GpiLoadBitmap(hPS, hmodBitmap, id, 0L, 0L) )
  639.    {
  640.    if (    pimgbtn->hbmDisabled )
  641.        GpiDeleteBitmap(pimgbtn->hbmDisabled);
  642.    pimgbtn->hbmDisabled    = hbm;
  643.    }
  644. else
  645.    if (    hbm = GpiLoadBitmap(hPS, hmodDLL, IDB_DEFAULTDISABLED, 0L, 0L) )
  646.        {
  647.        if ( pimgbtn->hbmDisabled )
  648.        GpiDeleteBitmap(pimgbtn->hbmDisabled);
  649.        pimgbtn->hbmDisabled = hbm;
  650.        }
  651.                /* Get the size of the bitmap that has been    */
  652.                /* loaded to allow the proper positioning of it    */
  653.                /* within the final button            */
  654.  
  655. GpiQueryBitmapParameters(pimgbtn->hbmDisabled, &bmpi);
  656. pimgbtn->cxDisabled = bmpi.cx;
  657. pimgbtn->cyDisabled = bmpi.cy;
  658.  
  659.                /* Release the temporary    presentation space    */
  660. WinReleasePS(hPS);
  661. }
  662. #pragma    subtitle("   Image Button Control - Presentation Parameters Retrieval Procedure")
  663. #pragma    page( )
  664.  
  665. /* --- lGetPresParam ----------------------------------    [ Private ] ---    */
  666. /*                                    */
  667. /*     This function is    used to    retrieve a presentation    parameter    */
  668. /*     that may    be present.  If    the presentation parameter is not,    */
  669. /*     the default colour passed to the    function will be used.        */
  670. /*                                    */
  671. /*     Upon Entry:                            */
  672. /*                                    */
  673. /*     HWND  hWnd;     = Window    Handle                    */
  674. /*     ULONG ulID1;    = Presentation Parameter    1 ID            */
  675. /*     ULONG ulID2;    = Presentation Parameter    2 ID            */
  676. /*     LONG  lDefault; = Default Colour                    */
  677. /*                                    */
  678. /*     Upon Exit:                            */
  679. /*                                    */
  680. /*     lGetPresParam = Colour to Use                    */
  681. /*                                    */
  682. /* --------------------------------------------------------------------    */
  683.  
  684. static LONG lGetPresParam(HWND hWnd, ULONG ulID1, ULONG    ulID2, LONG lDefault)
  685.  
  686. {
  687. HPS   hPS;               /* Presentation Space Handle        */
  688. LONG  lClr;               /* Presentation Parameter Colour    */
  689. ULONG ulID;               /* Presentation Parameter ID        */
  690.  
  691. if ( WinQueryPresParam(hWnd, ulID1, ulID2, &ulID, 4, (PVOID)&lClr,
  692.                QPF_NOINHERIT | QPF_ID1COLORINDEX | QPF_ID2COLORINDEX | QPF_PURERGBCOLOR) )
  693.    return(lClr);
  694. else
  695.                /* Check    to see if the colour requested as the    */
  696.                /* default is a SYSCLR_*    which is a special    */
  697.                /* colour index.     When the case,    use the        */
  698.                /* specific routine to determine    the colour of    */
  699.                /* the system colour index that is provided    */
  700.                /* through OS/2                    */
  701.  
  702.    if (    (lDefault >= SYSCLR_SHADOWHILITEBGND) &&
  703.     (lDefault <= SYSCLR_HELPHILITE)    )
  704.        return(WinQuerySysColor(HWND_DESKTOP, lDefault, 0L));
  705.    else
  706.        if ( (lClr = GpiQueryRGBColor(hPS = WinGetPS(hWnd),
  707.                      LCOLOPT_REALIZED, lDefault)) == GPI_ALTERROR )
  708.        {
  709.        WinReleasePS(hPS);
  710.        return(lDefault);
  711.        }
  712.        else
  713.        {
  714.        WinReleasePS(hPS);
  715.        return(lClr);
  716.        }
  717. }
  718. #pragma    subtitle("   Image Button Control - Default Colours Procedure")
  719. #pragma    page( )
  720.  
  721. /* --- SetDefaultColours ------------------------------    [ Private ] ---    */
  722. /*                                    */
  723. /*     This function is    used to    set the    default    colours    that the    */
  724. /*     image button should use within the internal paint routines.    */
  725. /*     The colour can either be    a presentation parameter that has    */
  726. /*     been set    or it can be the default colour    as defined within    */
  727. /*     control.                                */
  728. /*                                    */
  729. /*     Upon Entry:                            */
  730. /*                                    */
  731. /*     HWND    hWnd;    = Window Handle                    */
  732. /*     PIMGBTN pimgbtn;    = Image    Button Structure Pointer        */
  733. /*                                    */
  734. /*     Upon Exit:                            */
  735. /*                                    */
  736. /*     Nothing                                */
  737. /*                                    */
  738. /* --------------------------------------------------------------------    */
  739.  
  740. static VOID SetDefaultColours(HWND hWnd, PIMGBTN pimgbtn)
  741.  
  742. {
  743. HPS  hPS;               /* Presentation Space        */
  744. LONG lClr;               /* Colour                */
  745.  
  746.                /* Set up the colours that will be used within    */
  747.                /* the painting of the control.    The colour    */
  748.                /* indices are:                    */
  749.                /*                        */
  750.                /* 0 : Foreground (PP_FOREGROUND*)        */
  751.                /* 1 : Background (PP_BACKGROUND*)        */
  752.                /* 2 : Hilight Foreground (PP_HILITEFOREGROUND*)    */
  753.                /* 3 : Hilight Background (PP_HILITEBACKGROUND*)    */
  754.                /* 4 : Disabled Foreground (PP_DISABLEDFORE*)    */
  755.                /* 5 : Disabled Foreground (PP_DISABLEDFORE*)    */
  756.                /* 6 : Border (PP_BORDER*)            */
  757.  
  758. pimgbtn->aClr[0] = lGetPresParam(hWnd, PP_FOREGROUNDCOLOR,
  759.                  PP_FOREGROUNDCOLORINDEX,
  760.                  SYSCLR_OUTPUTTEXT);
  761. pimgbtn->aClr[1] = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR,
  762.                  PP_BACKGROUNDCOLORINDEX,
  763.                  SYSCLR_FIELDBACKGROUND);
  764. pimgbtn->aClr[2] = lGetPresParam(hWnd, PP_HILITEFOREGROUNDCOLOR,
  765.                  PP_HILITEFOREGROUNDCOLORINDEX,
  766.                  SYSCLR_OUTPUTTEXT);
  767. pimgbtn->aClr[3] = lGetPresParam(hWnd, PP_HILITEBACKGROUNDCOLOR,
  768.                  PP_HILITEBACKGROUNDCOLORINDEX,
  769.                  SYSCLR_BACKGROUND);
  770. pimgbtn->aClr[4] = lGetPresParam(hWnd, PP_DISABLEDFOREGROUNDCOLOR,
  771.                  PP_DISABLEDFOREGROUNDCOLORINDEX,
  772.                  SYSCLR_OUTPUTTEXT);
  773. pimgbtn->aClr[5] = lGetPresParam(hWnd, PP_DISABLEDBACKGROUNDCOLOR,
  774.                  PP_DISABLEDBACKGROUNDCOLORINDEX,
  775.                  SYSCLR_BACKGROUND);
  776. pimgbtn->aClr[6] = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR,
  777.                  PP_BACKGROUNDCOLORINDEX,
  778.                  SYSCLR_BUTTONDARK);
  779.  
  780. if ( (lClr = GpiQueryRGBColor(hPS = WinGetPS(hWnd),
  781.                   LCOLOPT_REALIZED,    SYSCLR_BUTTONDARK)) == GPI_ALTERROR )
  782.    pimgbtn->lButtonShadow = SYSCLR_BUTTONDARK;
  783. else
  784.    pimgbtn->lButtonShadow = lClr;
  785.  
  786. if ( (lClr = GpiQueryRGBColor(hPS, LCOLOPT_REALIZED,
  787.                   SYSCLR_BUTTONMIDDLE)) == GPI_ALTERROR )
  788.    pimgbtn->lButtonFace    = SYSCLR_BUTTONMIDDLE;
  789. else
  790.    pimgbtn->lButtonFace    = lClr;
  791.  
  792. if ( (lClr = GpiQueryRGBColor(hPS, LCOLOPT_REALIZED,
  793.                   SYSCLR_BUTTONLIGHT)) == GPI_ALTERROR )
  794.    pimgbtn->lButtonReflect = SYSCLR_BUTTONLIGHT;
  795. else
  796.    pimgbtn->lButtonReflect = lClr;
  797.  
  798. WinReleasePS(hPS);
  799. }
  800. #pragma    subtitle("   Image Button Control - Control Window Procedure")
  801. #pragma    page( )
  802.  
  803. /* --- ImageBtnWndProc ------------------------------------------------    */
  804. /*                                    */
  805. /*     This function is    used to    process    the messages for the image    */
  806. /*     button control.                            */
  807. /*                                    */
  808. /*     Upon Entry:                            */
  809. /*                                    */
  810. /*     HWND   hWnd; = Window Handle                    */
  811. /*     ULONG  msg;  = PM Message                    */
  812. /*     MPARAM mp1;  = Message Parameter    1                */
  813. /*     MPARAM mp2;  = Message Parameter    2                */
  814. /*                                    */
  815. /*     Upon Exit:                            */
  816. /*                                    */
  817. /*     ImageBtnWndProc = Message Handling Result            */
  818. /*                                    */
  819. /* --------------------------------------------------------------------    */
  820.  
  821. MRESULT    EXPENTRY ImageBtnWndProc(HWND hWnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  822.  
  823. {
  824. BITMAPINFOHEADER bmpi;           /* Bitmap Info Header        */
  825. CHAR         ch;           /* Character    Holder            */
  826. HBITMAP         hbm;           /* Bitmap Handle            */
  827. HPS         hPS;           /* Presentation Space Handle        */
  828. LONG         lClr;           /* Presentation Parameter Colour    */
  829. PCHAR         pch;           /* Character    String Pointer        */
  830. PCREATESTRUCT     pcrst;           /* Create Structure Pointer        */
  831. PIMAGEBUTTON     pib;           /* Image Button CTLDATA Pointer    */
  832. PIMGBTN         pimgbtn;       /* Image Button Structure Pointer    */
  833. POINTL         ptl;           /* Drawing Point            */
  834. PWNDPARAMS     pwprm;           /* Window Parameters    Pointer        */
  835. RECTL         rcl;           /* Rectangle    Holder            */
  836. ULONG         ulID;           /* Presentation Parameter ID        */
  837.  
  838. switch ( msg )
  839.    {
  840.  
  841. /************************************************************************/
  842. /************************************************************************/
  843. /*                                    */
  844. /* Part    1: Control creation coding                    */
  845. /*                                    */
  846. /************************************************************************/
  847. /************************************************************************/
  848.  
  849.    /*********************************************************************/
  850.    /*  Control creation                            */
  851.    /*********************************************************************/
  852.  
  853.    case    WM_CREATE :
  854.                /* Get the address of the CTLDATA structure that    */
  855.                /* may contain the bitmap information that the    */
  856.                /* control can use during its creation instead    */
  857.                /* of using messages to set the button images    */
  858.  
  859.        if ( pib    = (PIMAGEBUTTON)PVOIDFROMMP(mp1) )
  860.  
  861.                /* Check    to see that the    structure passed is    */
  862.                /* what is expected and if not, return        */
  863.                /* indicating that the control window should    */
  864.                /* not be further created            */
  865.  
  866.                /*************************************************/
  867.                /*  NOTE:   OS/2    2.0 requires the first element    */
  868.                /*       of the CTLDATA structure to be the    */
  869.                /*       size    of the structure and this    */
  870.                /*       value must be less than 64 KB    */
  871.                /*************************************************/
  872.  
  873.        if (    (pib->cb != sizeof(IMAGEBUTTON)) )
  874.            return(MRFROMLONG(TRUE));
  875.  
  876.                /* Allocate memory for internal control data    */
  877.  
  878.        DosAllocMem((PPVOID)&pimgbtn, sizeof(IMGBTN),
  879.            PAG_READ | PAG_WRITE    | PAG_COMMIT);
  880.  
  881.                /* Save the address of the internal control data    */
  882.                /* in the control's reserved memory to allow it  */
  883.                /* to be    referenced as required by the control    */
  884.  
  885.        WinSetWindowPtr(hWnd, QUCWP_WNDP, (PVOID)pimgbtn);
  886.  
  887.                /* Load each of the image bitmaps from the    */
  888.                /* calling executable and create    a bitmap that    */
  889.                /* will be shown    in each    button when the    ID for    */
  890.                /* bitmaps are provided otherwise use the    */
  891.                /* images contained within the control DLL    */
  892.  
  893.        LoadBitmaps(pib,    pimgbtn, (HMODULE)NULL);
  894.  
  895.                /* Get the control's creation structure address  */
  896.                /* to copy the relevant information such    as the    */
  897.                /* size,    position and text of the control into    */
  898.                /* the internal control data            */
  899.  
  900.        pcrst = (PCREATESTRUCT)PVOIDFROMMP(mp2);
  901.  
  902.                /* Save the owner and parent of the control so    */
  903.                /* notification messages    can be sent back to    */
  904.                /* the proper locations within the owning    */
  905.                /* application                    */
  906.  
  907.        pimgbtn->hwndOwner  = pcrst->hwndOwner;
  908.        pimgbtn->hwndParent = pcrst->hwndParent;
  909.  
  910.                /* Save the ID of the control and set the    */
  911.                /* initial position of the control to up    and    */
  912.                /* save the default style along with the    normal    */
  913.                /* arrow    pointer    handle which will be used when    */
  914.                /* the pointer passes over the control        */
  915.  
  916.        pimgbtn->id       = pcrst->id;
  917.        pimgbtn->flState       = IBS_UP;
  918.        pimgbtn->flStyle       = pcrst->flStyle;
  919.        pimgbtn->hptrArrow  = WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW,
  920.                         FALSE);
  921.  
  922.                /* Get the text of the control and save within    */
  923.                /* the internal control data            */
  924.  
  925.        strcpy(pimgbtn->szText, pcrst->pszText);
  926.  
  927.                /* Set up the colours that will be used within    */
  928.                /* the painting of the control            */
  929.  
  930.        SetDefaultColours(hWnd, pimgbtn);
  931.  
  932.                /* Check    to see if the user provided font that    */
  933.                /* should override the default font that    would    */
  934.                /* be set                    */
  935.  
  936.        if ( !WinQueryPresParam(hWnd, PP_FONTNAMESIZE, 0L, &ulID, 4,
  937.                    (PVOID)&lClr, QPF_NOINHERIT) )
  938.  
  939.                /* System indicates font    not set    since no data    */
  940.                /* was returned,    therefore set default font for    */
  941.                /* the control                    */
  942.  
  943.        WinSetPresParam(hWnd, PP_FONTNAMESIZE, 7L, (PVOID)"8.Helv");
  944.  
  945.                /* Save the initial size    of the control        */
  946.  
  947.        SizeButton(hWnd,    0, 0, pcrst->cx, pcrst->cy);
  948.        break;
  949.  
  950. /************************************************************************/
  951. /************************************************************************/
  952. /*                                    */
  953. /* Part    2: Control text    and colour support coding            */
  954. /*                                    */
  955. /************************************************************************/
  956. /************************************************************************/
  957.  
  958.    /*********************************************************************/
  959.    /*  Process window parameters setting                */
  960.    /*********************************************************************/
  961.  
  962.    case    WM_SETWINDOWPARAMS :
  963.  
  964.                /* Get the address for the windows parameters    */
  965.                /* structure                    */
  966.  
  967.        pwprm = (PWNDPARAMS)PVOIDFROMMP(mp1);
  968.  
  969.                /* Check    to see if the text for the control is    */
  970.                /* being    set                    */
  971.  
  972.        if ( pwprm->fsStatus & WPM_TEXT )
  973.        {
  974.                /* Text being set, get the address of the text    */
  975.                /* string stored    in the heap            */
  976.  
  977.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  978.  
  979.                /* Check    to see if any text is being set        */
  980.  
  981.        if (    pwprm->cchText )
  982.  
  983.                /* Check    to make    sure that the text that    is to    */
  984.                /* be set is not    greater    than the memory        */
  985.                /* allocated                    */
  986.  
  987.            if ( pwprm->cchText > 255 )
  988.            {
  989.            strncpy(pimgbtn->szText, pwprm->pszText, 255);
  990.            pimgbtn->szText[255]    = 0;
  991.            }
  992.            else
  993.            strcpy(pimgbtn->szText, pwprm->pszText);
  994.        else
  995.                /* No text is being set,    clear any existing text    */
  996.  
  997.            pimgbtn->szText[0] = 0;
  998.        }
  999.        break;
  1000.  
  1001.    /*********************************************************************/
  1002.    /*  Process window parameters query                    */
  1003.    /*********************************************************************/
  1004.  
  1005.    case    WM_QUERYWINDOWPARAMS :
  1006.  
  1007.                /* Get the address for the windows parameters    */
  1008.                /* structure                    */
  1009.  
  1010.        pwprm = (PWNDPARAMS)PVOIDFROMMP(mp1);
  1011.  
  1012.                /* Determine the    type of    query            */
  1013.  
  1014.        switch (    pwprm->fsStatus    )
  1015.        {
  1016.                /* Query    type:  get text                */
  1017.  
  1018.        case    WPM_TEXT :
  1019.  
  1020.                /* Text being asked for,    get the    address    of the    */
  1021.                /* text string stored in    the heap        */
  1022.  
  1023.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1024.  
  1025.                /* Copy the text    from the string    to the        */
  1026.                /* structure                    */
  1027.  
  1028.            strcpy(pwprm->pszText, pimgbtn->szText);
  1029.            break;
  1030.                /* Query    type:  get text    length            */
  1031.  
  1032.        case    WPM_CCHTEXT :
  1033.  
  1034.                /* Text length being asked for, get the address    */
  1035.                /* of the text string stored in the heap        */
  1036.  
  1037.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1038.  
  1039.                /* Place    the length the string within the    */
  1040.                /* structure                    */
  1041.  
  1042.            pwprm->cchText =    (SHORT)strlen(pimgbtn->szText);
  1043.            break;
  1044.                /* Query    type:  get control data    length        */
  1045.  
  1046.        case    WPM_CBCTLDATA :
  1047.  
  1048.                /* Set the control data length to zero        */
  1049.  
  1050.            pwprm->cbCtlData    = 0;
  1051.            break;
  1052.  
  1053.        default :
  1054.            return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  1055.        }
  1056.        break;
  1057.  
  1058.    /*********************************************************************/
  1059.    /*  Presentation parameters changed,    record the change internally    */
  1060.    /*********************************************************************/
  1061.  
  1062.    case    WM_PRESPARAMCHANGED :
  1063.  
  1064.                /* Check    to see if an individual    presentation    */
  1065.                /* parameter has    changed    if so, get the new    */
  1066.                /* colour value for use by the painting routines    */
  1067.  
  1068.        if ( LONGFROMMP(mp1) && (LONGFROMMP(mp1)    < PP_FONTNAMESIZE) )
  1069.        {
  1070.                /* Get the address of the control info from the    */
  1071.                /* control's reserved memory                     */
  1072.  
  1073.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1074.  
  1075.                /* Get the new presentation parameter colour for    */
  1076.                /* the presentation parameter that has changed.    */
  1077.                /* Get the colour as a RGB value    so as to be    */
  1078.                /* able to get an exact value and not an        */
  1079.                /* approximation    which could happen if the    */
  1080.                /* presentation parameter was set as a RGB but    */
  1081.                /* queried as an    index.    When WinQueryPresParam    */
  1082.                /* returns a 0, it indicates that no        */
  1083.                /* presentation parameter set and the default    */
  1084.                /* colours should be used.            */
  1085.  
  1086.        switch ( LONGFROMMP(mp1) )
  1087.            {
  1088.            case PP_FOREGROUNDCOLOR :
  1089.            case PP_FOREGROUNDCOLORINDEX :
  1090.            pimgbtn->aClr[0] = lGetPresParam(hWnd, PP_FOREGROUNDCOLOR,
  1091.                             PP_FOREGROUNDCOLORINDEX,
  1092.                             SYSCLR_OUTPUTTEXT);
  1093.            break;
  1094.  
  1095.            case PP_BACKGROUNDCOLOR :
  1096.            case PP_BACKGROUNDCOLORINDEX :
  1097.            pimgbtn->aClr[1] = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR,
  1098.                             PP_BACKGROUNDCOLORINDEX,
  1099.                             SYSCLR_BACKGROUND);
  1100.            break;
  1101.  
  1102.            case PP_HILITEFOREGROUNDCOLOR :
  1103.            case PP_HILITEFOREGROUNDCOLORINDEX :
  1104.            pimgbtn->aClr[2] = lGetPresParam(hWnd, PP_HILITEFOREGROUNDCOLOR,
  1105.                             PP_HILITEFOREGROUNDCOLORINDEX,
  1106.                             SYSCLR_OUTPUTTEXT);
  1107.            break;
  1108.  
  1109.            case PP_HILITEBACKGROUNDCOLOR :
  1110.            case PP_HILITEBACKGROUNDCOLORINDEX :
  1111.            pimgbtn->aClr[3] = lGetPresParam(hWnd, PP_HILITEBACKGROUNDCOLOR,
  1112.                             PP_HILITEBACKGROUNDCOLORINDEX,
  1113.                             SYSCLR_BACKGROUND);
  1114.            break;
  1115.  
  1116.            case PP_DISABLEDFOREGROUNDCOLOR :
  1117.            case PP_DISABLEDFOREGROUNDCOLORINDEX :
  1118.            pimgbtn->aClr[4] = lGetPresParam(hWnd, PP_DISABLEDFOREGROUNDCOLOR,
  1119.                             PP_DISABLEDFOREGROUNDCOLORINDEX,
  1120.                             SYSCLR_OUTPUTTEXT);
  1121.            break;
  1122.  
  1123.            case PP_DISABLEDBACKGROUNDCOLOR :
  1124.            case PP_DISABLEDBACKGROUNDCOLORINDEX :
  1125.            pimgbtn->aClr[5] = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR,
  1126.                             PP_BACKGROUNDCOLORINDEX,
  1127.                             SYSCLR_BACKGROUND);
  1128.            break;
  1129.  
  1130.            case PP_BORDERCOLOR :
  1131.            case PP_BORDERCOLORINDEX    :
  1132.            pimgbtn->aClr[6] = lGetPresParam(hWnd, PP_BACKGROUNDCOLOR,
  1133.                             PP_BACKGROUNDCOLORINDEX,
  1134.                             SYSCLR_BUTTONDARK);
  1135.            break;
  1136.            }
  1137.                /* Invalidate the button    to force to use    the    */
  1138.                /* new colours just set or removed        */
  1139.  
  1140.            WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1141.        }
  1142.        else
  1143.                /* Determine if the Scheme Palette has forced a    */
  1144.                /* global scheme    update in which    case, check all    */
  1145.                /* of the presentation parameters to see    if they    */
  1146.                /* have been added or removed            */
  1147.  
  1148.        if (    LONGFROMMP(mp1)    == 0L )
  1149.  
  1150.                /* Set up the colours that will be used within    */
  1151.                /* the painting of the control.            */
  1152.  
  1153.            SetDefaultColours(hWnd,
  1154.                  pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP));
  1155.        break;
  1156.  
  1157. /************************************************************************/
  1158. /************************************************************************/
  1159. /*                                    */
  1160. /* Part    3: Control size    and position coding                */
  1161. /*                                    */
  1162. /************************************************************************/
  1163. /************************************************************************/
  1164.  
  1165.    /*********************************************************************/
  1166.    /*  Size of the control changing                    */
  1167.    /*********************************************************************/
  1168.  
  1169.    case    WM_SIZE    :
  1170.                /* Get the actual position of the control as a    */
  1171.                /* rectangle to allow it    to be saved within the    */
  1172.                /* internal control data                */
  1173.  
  1174.        WinQueryWindowRect(hWnd,    &rcl);
  1175.  
  1176.                /* Save the new control position    and size    */
  1177.  
  1178.        SizeButton(hWnd,    rcl.xLeft, rcl.yBottom,
  1179.           (rcl.xRight -    rcl.xLeft),
  1180.           (rcl.yTop   -    rcl.yBottom));
  1181.        break;
  1182.  
  1183. /************************************************************************/
  1184. /************************************************************************/
  1185. /*                                    */
  1186. /* Part    4: Control enable/disable and focus/defocus coding        */
  1187. /*                                    */
  1188. /************************************************************************/
  1189. /************************************************************************/
  1190.  
  1191.    /*********************************************************************/
  1192.    /*  Control is being    activated or deactivated            */
  1193.    /*********************************************************************/
  1194.  
  1195.    case    WM_ACTIVATE :
  1196.                /* When the control is being activated or    */
  1197.                /* deactivated, make sure that the control    */
  1198.                /* responds properly to help requests when it    */
  1199.                /* has the focus                    */
  1200.  
  1201.        if ( SHORT1FROMMP(mp1) )
  1202.        WinSendMsg(WinQueryHelpInstance(hWnd),
  1203.               HM_SET_ACTIVE_WINDOW,
  1204.               MPFROMHWND(WinQueryWindow(hWnd, QW_PARENT)),
  1205.               MPFROMHWND(WinQueryWindow(hWnd, QW_PARENT)));
  1206.        else
  1207.        WinSendMsg(WinQueryHelpInstance(hWnd),
  1208.               HM_SET_ACTIVE_WINDOW, 0L,    0L);
  1209.        break;
  1210.  
  1211.    /*********************************************************************/
  1212.    /*  Control is being    disable    or enabled                */
  1213.    /*********************************************************************/
  1214.  
  1215.    case    WM_ENABLE :
  1216.  
  1217.                /* Get the address of the control info from the    */
  1218.                /* control's reserved memory                     */
  1219.  
  1220.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1221.  
  1222.                /* Check    to see if the control is being disabled    */
  1223.                /* or enabled and set the state of the control    */
  1224.                /* within ther internal control data        */
  1225.  
  1226.        if ( (BOOL)SHORT1FROMMP(mp1) )
  1227.        pimgbtn->flState &= ~IBS_DISABLED;
  1228.        else
  1229.        pimgbtn->flState |= IBS_DISABLED;
  1230.  
  1231.                /* Force    the repainting of the control as its    */
  1232.                /* state    is changing                */
  1233.  
  1234.        WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1235.        break;
  1236.  
  1237.    /*********************************************************************/
  1238.    /*  Control is gaining or losing focus                */
  1239.    /*********************************************************************/
  1240.  
  1241.    case    WM_SETFOCUS :
  1242.  
  1243.                /* Get the address of the control info from the    */
  1244.                /* control's reserved memory                     */
  1245.  
  1246.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1247.  
  1248.                /* Set the focus    state for the control based    */
  1249.                /* on the information from the message        */
  1250.  
  1251.        pimgbtn->fFocus = (BOOL)SHORT1FROMMP(mp2);
  1252.  
  1253.                /* Force    the repainting of the control as its    */
  1254.                /* state    is changing                */
  1255.  
  1256.        WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1257.        break;
  1258.  
  1259.    /*********************************************************************/
  1260.    /*  Control is gaining or losing selection                */
  1261.    /*********************************************************************/
  1262.  
  1263.    case    WM_SETSELECTION    :
  1264.  
  1265.                /* Get the address of the control info from the    */
  1266.                /* control's reserved memory                     */
  1267.  
  1268.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1269.  
  1270.                /* Set the focus    state for the control based    */
  1271.                /* on the information from the message        */
  1272.  
  1273.        pimgbtn->fFocus = (BOOL)SHORT1FROMMP(mp1);
  1274.  
  1275.                /* Force    the repainting of the control as its    */
  1276.                /* state    is changing                */
  1277.  
  1278.        WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1279.        break;
  1280.  
  1281.    /*********************************************************************/
  1282.    /*  Control is gaining or losing selection                */
  1283.    /*********************************************************************/
  1284.  
  1285.    case    WM_QUERYDLGCODE    :
  1286.        return(MRFROMLONG(DLGC_PUSHBUTTON));
  1287.  
  1288. /************************************************************************/
  1289. /************************************************************************/
  1290. /*                                    */
  1291. /* Part    5: User    interaction coding for keyboard    and mouse        */
  1292. /*                                    */
  1293. /************************************************************************/
  1294. /************************************************************************/
  1295.  
  1296.    /*********************************************************************/
  1297.    /*  Check for key strokes                        */
  1298.    /*********************************************************************/
  1299.  
  1300.    case    WM_CHAR    :
  1301.                /* Check    for the    key up flag in which case the    */
  1302.                /* condition should be ignored            */
  1303.  
  1304.        if ( SHORT1FROMMP(mp1) &    KC_KEYUP )
  1305.        return(0L);
  1306.                /* Check    for virtual keys            */
  1307.  
  1308.        if ( SHORT1FROMMP(mp1) &    KC_VIRTUALKEY )
  1309.        switch ( SHORT2FROMMP(mp2) )
  1310.            {
  1311.            case VK_ENTER :
  1312.            case VK_NEWLINE :
  1313.  
  1314.                /* Get the address of the control info from the    */
  1315.                /* control's reserved memory                     */
  1316.  
  1317.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1318.  
  1319.            pimgbtn->flState = IBS_DOWN;
  1320.            WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1321.  
  1322.                /* Post a message to the    main window using the    */
  1323.                /* command message value    to inform the control    */
  1324.                /* owner    that the button    has been selected    */
  1325.  
  1326.            WinSendMsg(pimgbtn->hwndOwner, WM_COMMAND,
  1327.                   MPFROMSHORT(pimgbtn->id),
  1328.                   MPFROM2SHORT(FALSE, CMDSRC_OTHER));
  1329.  
  1330.                /* Invalidate the button    image to update    it from    */
  1331.                /* down position                    */
  1332.  
  1333.            pimgbtn->flState = IBS_UP;
  1334.            WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1335.            return(0L);
  1336.  
  1337.            case VK_TAB :
  1338.                /* Get the address of the control info from the    */
  1339.                /* control's reserved memory                     */
  1340.  
  1341.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1342.  
  1343.                /* TAB key pressed, determine which control is    */
  1344.                /* the next tab stop and    set the    focus on that    */
  1345.                /* control                    */
  1346.  
  1347.            WinSetFocus(HWND_DESKTOP,
  1348.                    WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
  1349.                           EDI_NEXTTABITEM));
  1350.            return(0L);
  1351.  
  1352.            case VK_RIGHT :
  1353.            case VK_DOWN :
  1354.                /* Get the address of the control info from the    */
  1355.                /* control's reserved memory                     */
  1356.  
  1357.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1358.  
  1359.                /* Right    or down    arrow key pressed, determine    */
  1360.                /* which    control    is the next entry and set the    */
  1361.                /* focus    on that    control                */
  1362.  
  1363.            WinSetFocus(HWND_DESKTOP,
  1364.                    WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
  1365.                           EDI_NEXTGROUPITEM));
  1366.            return(0L);
  1367.  
  1368.            case VK_BACKTAB :
  1369.                /* Get the address of the control info from the    */
  1370.                /* control's reserved memory                     */
  1371.  
  1372.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1373.  
  1374.                /* Shift+TAB key    pressed, determine which    */
  1375.                /* control is the previous tab stop and set the    */
  1376.                /* focus    on that    control                */
  1377.  
  1378.            WinSetFocus(HWND_DESKTOP,
  1379.                    WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
  1380.                           EDI_PREVTABITEM));
  1381.            return(0L);
  1382.  
  1383.            case VK_LEFT :
  1384.            case VK_UP :
  1385.                /* Get the address of the control info from the    */
  1386.                /* control's reserved memory                     */
  1387.  
  1388.            pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1389.  
  1390.                /* Left or up arrow key pressed,    determine    */
  1391.                /* which    control    is the previous    entry and set    */
  1392.                /* the focus on that control            */
  1393.  
  1394.            WinSetFocus(HWND_DESKTOP,
  1395.                    WinEnumDlgItem(pimgbtn->hwndOwner, hWnd,
  1396.                           EDI_PREVGROUPITEM));
  1397.            return(0L);
  1398.            }
  1399.                /* Virtual key not TAB or Shift+TAB, fall    */
  1400.                /* through to default window procedure        */
  1401.  
  1402.        return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  1403.  
  1404.    /*********************************************************************/
  1405.    /*  Button 1    pressed                            */
  1406.    /*********************************************************************/
  1407.  
  1408.    case    WM_BUTTON1DOWN :
  1409.                /* Get the address of the control info from the    */
  1410.                /* control's reserved memory                     */
  1411.  
  1412.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1413.  
  1414.                /* Check    to see if the button is    disabled and if    */
  1415.                /* the case, ignore the button request        */
  1416.  
  1417.        if ( pimgbtn->flState & IBS_DISABLED )
  1418.        return(0L);
  1419.        else
  1420.        {
  1421.                /* Post a message to the    main window using the    */
  1422.                /* command message value    to inform the control    */
  1423.                /* owner    that the button    has been selected    */
  1424.  
  1425.        ptl.x = (LONG)SHORT1FROMMP(mp1);
  1426.        ptl.y = (LONG)SHORT2FROMMP(mp1);
  1427.        if (    WinPtInRect((HAB)NULL, &pimgbtn->rclHitTest, &ptl) )
  1428.            {
  1429.                /* Since    the user has clicked the mouse pointer    */
  1430.                /* on the control, set the state    of the button    */
  1431.                /* as being down    and in capture mode in case the    */
  1432.                /* user moves the mouse outside of the area of    */
  1433.                /* control while    keeping    button 1 of the    mouse    */
  1434.                /* down                        */
  1435.  
  1436.            pimgbtn->flState    = IBS_DOWN | IBS_CAPTURE;
  1437.  
  1438.                /* Set the mouse    capture    to follow the movement    */
  1439.                /* of the mouse pointer until the mouse button    */
  1440.                /* is released                    */
  1441.  
  1442.            WinSetCapture(HWND_DESKTOP, hWnd);
  1443.  
  1444.                /* Remove focus from the    control    if it has been    */
  1445.                /* selected                    */
  1446.  
  1447.            pimgbtn->fFocus = FALSE;
  1448.  
  1449.                /* Force    the repainting of the control        */
  1450.  
  1451.            WinInvalidateRect(hWnd, NULL, TRUE);
  1452.  
  1453.                /* Since    the control is receiving the focus,    */
  1454.                /* make sure the    focus changes from the current    */
  1455.                /* control selected within the window or        */
  1456.                /* dialogue to this control            */
  1457.  
  1458.            WinSetFocus(HWND_DESKTOP, hWnd);
  1459.            }
  1460.        }
  1461.        break;
  1462.  
  1463.    /*********************************************************************/
  1464.    /*  Button 1    released                        */
  1465.    /*********************************************************************/
  1466.  
  1467.    case    WM_BUTTON1UP :
  1468.                /* Get the address of the control info from the    */
  1469.                /* control's reserved memory                     */
  1470.  
  1471.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1472.  
  1473.                /* Check    to see if the button is    disabled and if    */
  1474.                /* the case, ignore the button request        */
  1475.  
  1476.        if ( pimgbtn->flState & IBS_DISABLED )
  1477.        return(0L);
  1478.        else
  1479.        {
  1480.                /* Since    the user has clicked and released the    */
  1481.                /* mouse    pointer    on the control,    set the    state    */
  1482.                /* of the button    as being up and    remove the    */
  1483.                /* capture mode setting since interaction with    */
  1484.                /* the button only occurrs when the mouse    */
  1485.                /* button is depressed                */
  1486.  
  1487.        pimgbtn->flState = IBS_UP;
  1488.  
  1489.                /* Release the mouse capture since the user has    */
  1490.                /* released the mouse button            */
  1491.  
  1492.        WinSetCapture(HWND_DESKTOP, (HWND)NULL);
  1493.  
  1494.                /* Post a message to the    main window using the    */
  1495.                /* command message value    to inform the control    */
  1496.                /* owner    that the button    has been selected    */
  1497.  
  1498.        ptl.x = (LONG)SHORT1FROMMP(mp1);
  1499.        ptl.y = (LONG)SHORT2FROMMP(mp1);
  1500.        if (    WinPtInRect((HAB)NULL, &pimgbtn->rclHitTest, &ptl) )
  1501.            {
  1502.            WinPostMsg(pimgbtn->hwndOwner, WM_COMMAND,
  1503.               MPFROMSHORT(pimgbtn->id),
  1504.               MPFROM2SHORT(TRUE, CMDSRC_OTHER));
  1505.  
  1506.                /* Invalidate the button    image to update    it from    */
  1507.                /* down position                    */
  1508.  
  1509.            WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1510.  
  1511.                /* Since    the control is receiving the focus,    */
  1512.                /* make sure the    focus changes from the current    */
  1513.                /* control selected within the window or        */
  1514.                /* dialogue to this control            */
  1515.  
  1516.            WinSetFocus(HWND_DESKTOP, hWnd);
  1517.            }
  1518.        }
  1519.        break;
  1520.  
  1521.    /*********************************************************************/
  1522.    /* Process mouse movement over the button                */
  1523.    /*********************************************************************/
  1524.  
  1525.    case    WM_MOUSEMOVE :
  1526.                /* Get the address of the control info from the    */
  1527.                /* control's reserved memory                     */
  1528.  
  1529.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1530.  
  1531.                /* Check    to see if the mouse is in capture mode    */
  1532.                /* which    indicates that the user    has depressed    */
  1533.                /* button 1 of the mouse    and kept it down while    */
  1534.                /* moving the mouse pointer around        */
  1535.  
  1536.        if ( pimgbtn->flState & IBS_CAPTURE )
  1537.        {
  1538.                /* When in capture mode,    the control checks to    */
  1539.                /* see where the    pointer    is located such    that    */
  1540.                /* when the mouse pointer is outside the    control    */
  1541.                /* area,    the control's appearance is as though   */
  1542.                /* it is    in the up position.  When the pointer    */
  1543.                /* is within the    control    area, the down        */
  1544.                /* position of the control is shown.        */
  1545.  
  1546.        ptl.x = (LONG)SHORT1FROMMP(mp1);
  1547.        ptl.y = (LONG)SHORT2FROMMP(mp1);
  1548.  
  1549.                /* Check    to see where the mouse pointer is    */
  1550.                /* located within relationship to the control    */
  1551.  
  1552.        if (    !WinPtInRect((HAB)NULL,    &pimgbtn->rclHitTest, &ptl) )
  1553.            {
  1554.                /* The mouse is outside of the control area,    */
  1555.                /* check    to see if the control is currently    */
  1556.                /* shown    as down    and if the case, set it    to the    */
  1557.                /* up position internally and force it to be    */
  1558.                /* repainted in the up position            */
  1559.  
  1560.            if ( pimgbtn->flState & IBS_DOWN    )
  1561.            {
  1562.            pimgbtn->flState = IBS_UP | IBS_CAPTURE;
  1563.            WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1564.            }
  1565.            }
  1566.        else
  1567.                /* The mouse is inside of the control area,    */
  1568.                /* check    to see if the control is currently    */
  1569.                /* shown    as up and if the case, set it to the    */
  1570.                /* down position    internally and force it    to be    */
  1571.                /* repainted in the down    position        */
  1572.  
  1573.            if ( pimgbtn->flState & IBS_UP )
  1574.            {
  1575.            pimgbtn->flState = IBS_DOWN | IBS_CAPTURE;
  1576.            WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1577.            }
  1578.        }
  1579.                /* Send the WM_CONTROLPOINTER message to    the    */
  1580.                /* owner    of the control to allow    the owner of    */
  1581.                /* control to change the    pointer    shape from the    */
  1582.                /* current defined arrow    shape            */
  1583.  
  1584.        WinSetPointer(HWND_DESKTOP,
  1585.              (HPOINTER)WinSendMsg(pimgbtn->hwndOwner,
  1586.                       WM_CONTROLPOINTER,
  1587.                       MPFROMSHORT(pimgbtn->id),
  1588.                       MPFROMLONG(pimgbtn->hptrArrow)));
  1589.        break;
  1590.  
  1591.    /*********************************************************************/
  1592.    /*  DBCS character conversion requested                */
  1593.    /*********************************************************************/
  1594.  
  1595.    case    WM_QUERYCONVERTPOS :
  1596.  
  1597.                /* State    that conversion    should not occur    */
  1598.  
  1599.        return(MRFROMSHORT(QCP_NOCONVERT));
  1600.  
  1601.    /*********************************************************************/
  1602.    /*  Match mnemonic                            */
  1603.    /*********************************************************************/
  1604.  
  1605.    case    WM_MATCHMNEMONIC :
  1606.                /* Get the address of the control info from the    */
  1607.                /* control's reserved memory                     */
  1608.  
  1609.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1610.  
  1611.                /* Check    to see if a mnemonic symbol contained    */
  1612.                /* within the control text            */
  1613.  
  1614.        if ( pch    = strchr(pimgbtn->szText, '~') )
  1615.        {
  1616.                /* Mnemonic symbol found    within the text, get    */
  1617.                /* the character    and see    if the character    */
  1618.                /* matches that typed by    the user after        */
  1619.                /* converting any lower case characters to    */
  1620.                /* upper    case                    */
  1621.        ++pch;
  1622.        if (    (ch = CHAR1FROMMP(mp1))    > '`' )
  1623.            if ( ch < '{' )
  1624.            ch -= ' ';
  1625.  
  1626.                /* Check    to see if the mnemonic matches and    */
  1627.                /* if the case, indicate    a match    through    the    */
  1628.                /* return value which will cause    the BM_CLICK    */
  1629.                /* message to be    sent to    the control        */
  1630.  
  1631.        if (    *pch ==    ch )
  1632.            return(MRFROMLONG(TRUE));
  1633.        }
  1634.        break;
  1635.  
  1636.    /*********************************************************************/
  1637.    /*  Button Click                            */
  1638.    /*********************************************************************/
  1639.  
  1640.    case    BM_CLICK :
  1641.                /* The message is received only when the    control    */
  1642.                /* is processing    the mnemonic selection of the    */
  1643.                /* control.  The    message    is received since the    */
  1644.                /* control was designated as being a push button    */
  1645.                /* through the WM_QUERYDLGCODE.            */
  1646.  
  1647.                /* Get the address of the control info from the    */
  1648.                /* control's reserved memory                     */
  1649.  
  1650.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1651.  
  1652.        pimgbtn->flState    = IBS_DOWN;
  1653.        WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1654.  
  1655.                /* Post a message to the    main window using the    */
  1656.                /* command message value    to inform the control    */
  1657.                /* owner    that the button    has been selected    */
  1658.  
  1659.        WinSendMsg(pimgbtn->hwndOwner, WM_COMMAND,
  1660.           MPFROMSHORT(pimgbtn->id),
  1661.           MPFROM2SHORT(FALSE, CMDSRC_OTHER));
  1662.  
  1663.                /* Invalidate the button    image to update    it from    */
  1664.                /* down position                    */
  1665.  
  1666.        pimgbtn->flState    = IBS_UP;
  1667.        WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1668.        break;
  1669.  
  1670. /************************************************************************/
  1671. /************************************************************************/
  1672. /*                                    */
  1673. /* Part    6: Control painting and    appearance coding            */
  1674. /*                                    */
  1675. /************************************************************************/
  1676. /************************************************************************/
  1677.  
  1678.    /*********************************************************************/
  1679.    /*  Erase background                            */
  1680.    /*********************************************************************/
  1681.  
  1682.    case    WM_ERASEBACKGROUND :
  1683.  
  1684.                /* Have OS/2 Presentation Manager perform the    */
  1685.                /* background erase on behalf of    the button    */
  1686.  
  1687.        return(MRFROMLONG(TRUE));
  1688.  
  1689.    /*********************************************************************/
  1690.    /*  Paint the button                            */
  1691.    /*********************************************************************/
  1692.  
  1693.    case    WM_PAINT :
  1694.                /* Get the address of the control info from the    */
  1695.                /* control's reserved memory                     */
  1696.  
  1697.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1698.  
  1699.        if ( (WinQueryWindowULong(hWnd, QWL_STYLE) & IS_TEXTBELOWBTN) &&
  1700.         (pimgbtn->flStyle &    IS_TEXTONBTN) )
  1701.        {
  1702.        pimgbtn->flStyle &= ~IS_TEXTONBTN;
  1703.        pimgbtn->flStyle |=    IS_TEXTBELOWBTN;
  1704.        WinQueryWindowRect(hWnd, &rcl);
  1705.        SizeButton(hWnd, rcl.xLeft, rcl.yBottom,
  1706.               (rcl.xRight - rcl.xLeft),
  1707.               (rcl.yTop      - rcl.yBottom));
  1708.        }
  1709.        else
  1710.        if (    (WinQueryWindowULong(hWnd, QWL_STYLE) &    IS_TEXTONBTN) &&
  1711.         (pimgbtn->flStyle & IS_TEXTBELOWBTN) )
  1712.            {
  1713.            pimgbtn->flStyle    &= ~IS_TEXTBELOWBTN;
  1714.            pimgbtn->flStyle    |=  IS_TEXTONBTN;
  1715.            WinQueryWindowRect(hWnd,    &rcl);
  1716.            SizeButton(hWnd,    rcl.xLeft, rcl.yBottom,
  1717.               (rcl.xRight -    rcl.xLeft),
  1718.               (rcl.yTop   -    rcl.yBottom));
  1719.            }
  1720.                /* Get the presentation space for the control    */
  1721.                /* and set the colour table to RGB mode        */
  1722.  
  1723.        GpiCreateLogColorTable(hPS = WinBeginPaint(hWnd,    (HPS)NULL, (PRECTL)NULL),
  1724.                   0L, LCOLF_RGB, 0L, 0L, (PLONG)NULL);
  1725.  
  1726.                /* Get the presentation space for the control    */
  1727.                /* and fill the button area of the control with    */
  1728.                /* the colour for the button            */
  1729.  
  1730.        WinFillRect(hPS,    &pimgbtn->rclHitTest, pimgbtn->lButtonFace);
  1731.  
  1732.                /* Get the destenation point and    the bitmap    */
  1733.                /* rectangle to allow the bitmap    to be correctly    */
  1734.                /* positioned within the    control            */
  1735.  
  1736.        rcl = pimgbtn->rclSrc;
  1737.  
  1738.                /* Check    the state of the control such that the    */
  1739.                /* control is correctly offset            */
  1740.  
  1741.        if ( pimgbtn->flState & IBS_DOWN    )
  1742.        {
  1743.        ptl = pimgbtn->ptlDestDown;
  1744.        rcl = pimgbtn->rclSrcDown;
  1745.  
  1746.                /* Set the left edge colour of the control as    */
  1747.                /* shadowed since the button is in the down    */
  1748.                /* position                    */
  1749.  
  1750.        GpiSetColor(hPS, pimgbtn->lButtonShadow);
  1751.        hbm = pimgbtn->hbmDown;
  1752.        }
  1753.        else
  1754.        {
  1755.        if (    pimgbtn->flState & IBS_DISABLED    )
  1756.            {
  1757.            hbm = pimgbtn->hbmDisabled;
  1758.            ptl = pimgbtn->ptlDestDisabled;
  1759.            rcl = pimgbtn->rclSrcDisabled;
  1760.            }
  1761.        else
  1762.            {
  1763.            hbm = pimgbtn->hbm;
  1764.            ptl = pimgbtn->ptlDest;
  1765.            rcl = pimgbtn->rclSrc;
  1766.            }
  1767.                /* Set the left edge colour of the control as    */
  1768.                /* white    since the button is in the up position    */
  1769.  
  1770.        GpiSetColor(hPS, pimgbtn->lButtonReflect);
  1771.        }
  1772.                /* Draw the bitmap within the control.  Use the    */
  1773.                /* appropriate bitmap depending on whether or    */
  1774.                /* not the bitmap is diabled.            */
  1775.  
  1776.        WinDrawBitmap(hPS, hbm, &rcl, &ptl, 0L, 0L, DBM_IMAGEATTRS);
  1777.  
  1778.                /* Now begin the    process    of drawing the        */
  1779.                /* chamfering edges of the control.  Begin the    */
  1780.                /* drawing using    the lower left corner as the    */
  1781.                /* default starting point.  The co-ordinates    */
  1782.                /* for the chamfering have been defined as:    */
  1783.                /*                        */
  1784.                /*        1           2        */
  1785.                /*         +------------+            */
  1786.                /*         |          |            */
  1787.                /*         |          |            */
  1788.                /*         |          |            */
  1789.                /*         |          |            */
  1790.                /*           0 +------------+            */
  1791.                /*         4           3        */
  1792.  
  1793.        if ( pimgbtn->flState & IBS_DISABLED )
  1794.        GpiSetLineType(hPS, LINETYPE_ALTERNATE);
  1795.        else
  1796.        GpiSetLineType(hPS, LINETYPE_SOLID);
  1797.        GpiMove(hPS, pimgbtn->aptlShadow);
  1798.        GpiPolyLine(hPS,    5L, &pimgbtn->aptlShadow[1]);
  1799.  
  1800.                /* Check    to see if the control is not in    the    */
  1801.                /* down position    in which case the right    and    */
  1802.                /* bottom edge of the control needs to be    */
  1803.                /* drawn    in shawdow                */
  1804.  
  1805.        if ( (pimgbtn->flState &    IBS_DOWN) != IBS_DOWN )
  1806.        {
  1807.        GpiSetColor(hPS, pimgbtn->lButtonShadow);
  1808.        GpiMove(hPS,    &pimgbtn->aptlShadow[6]);
  1809.        GpiPolyLine(hPS, 5L,    &pimgbtn->aptlShadow[7]);
  1810.        }
  1811.        else
  1812.        {
  1813.        GpiSetColor(hPS, pimgbtn->lButtonReflect);
  1814.        GpiMove(hPS,    &pimgbtn->aptlShadow[6]);
  1815.        GpiPolyLine(hPS, 2L,    &pimgbtn->aptlShadow[7]);
  1816.        }
  1817.                /* Set the colour for the control outline to    */
  1818.                /* button dark so as to give it some definition    */
  1819.  
  1820.        GpiSetColor(hPS,    pimgbtn->lButtonShadow);
  1821.  
  1822.                /* This time instead of drawing a closed    four    */
  1823.                /* sided    object,    draw the object    as:        */
  1824.                /*                        */
  1825.                /*        1           2        */
  1826.                /*          ------------            */
  1827.                /*         |          |            */
  1828.                /*         |          |            */
  1829.                /*         |          |            */
  1830.                /*         |          |            */
  1831.                /*           0  ------------            */
  1832.                /*         4           3        */
  1833.  
  1834.        GpiMove(hPS, pimgbtn->aptlOutline);
  1835.        GpiPolyLine(hPS,    7L, &pimgbtn->aptlOutline[1]);
  1836.  
  1837.                /* Check    to see if any text associated with the    */
  1838.                /* control and if the case, draw    it according    */
  1839.                /* to the style set for the control        */
  1840.  
  1841.        if ( pimgbtn->szText[0] )
  1842.        {
  1843.                /* Position the starting    point of the text just    */
  1844.                /* up from the chamfer edge            */
  1845.  
  1846.        rcl = pimgbtn->rclText;
  1847.        if (    (pimgbtn->flState & IBS_DOWN) && (pimgbtn->flStyle & IS_TEXTONBTN) )
  1848.            {
  1849.                /* When the button is in    the down position,    */
  1850.                /* shift    the text down and to the right by two    */
  1851.                /* pixels to give the appearance    that the    */
  1852.                /* button is moving                */
  1853.  
  1854.            rcl.xLeft  += 2;
  1855.            rcl.xRight += 2;
  1856.            rcl.yBottom -= 2;
  1857.            rcl.yTop       -= 2;
  1858.            }
  1859.  
  1860.        GpiSetBackMix(hPS, BM_OVERPAINT);
  1861.  
  1862.                /* Draw the text    within the control        */
  1863.  
  1864.        WinDrawText(hPS, -1,    pimgbtn->szText, &rcl,
  1865.                pimgbtn->aClr[0], pimgbtn->aClr[1],
  1866.                (pimgbtn->flState & IBS_DISABLED    ? DT_HALFTONE :    0L) |
  1867.                DT_MNEMONIC | DT_CENTER | DT_VCENTER);
  1868.  
  1869.                /* Determine if the focus emphasis should be    */
  1870.                /* shown    for the    control.  When this is the    */
  1871.                /* case,    set the    colour for the dotted outline    */
  1872.                /* that will appear around the text of the    */
  1873.                /* control to be    the same as the    chamfered edges    */
  1874.                /* of the control.  When    no emphasis is        */
  1875.                /* required, set    the colour for the emphasis to    */
  1876.                /* be the same as the background    since this will    */
  1877.                /* allow    the emphasis to    be erased when the    */
  1878.                /* control loses    focus.                */
  1879.  
  1880.        if (    !(pimgbtn->flState & IBS_CAPTURE) )
  1881.            {
  1882.            if ( pimgbtn->fFocus )
  1883.            GpiSetColor(hPS, pimgbtn->lButtonShadow);
  1884.            else
  1885.            GpiSetColor(hPS, pimgbtn->aClr[1]);
  1886.  
  1887.                /* Set the line type for    the emphasis to    be    */
  1888.                /* every    other pixel                */
  1889.  
  1890.            GpiSetLineType(hPS, LINETYPE_ALTERNATE);
  1891.  
  1892.                /* Draw the emphasis using the precalculated    */
  1893.                /* co-ordinates                    */
  1894.  
  1895.            GpiMove(hPS, pimgbtn->aptlFocus);
  1896.            GpiPolyLine(hPS,    4L, &pimgbtn->aptlFocus[1]);
  1897.            }
  1898.        }
  1899.                /* Release the presentation space        */
  1900.        WinEndPaint(hPS);
  1901.        break;
  1902.  
  1903. /************************************************************************/
  1904. /************************************************************************/
  1905. /*                                    */
  1906. /* Part    7: Control defined message coding                */
  1907. /*                                    */
  1908. /************************************************************************/
  1909. /************************************************************************/
  1910.  
  1911.    /*********************************************************************/
  1912.    /*  Control Defined Message:     Load bitmaps                */
  1913.    /*********************************************************************/
  1914.  
  1915.    case    IM_LOADBITMAPS :
  1916.        if ( !(pib = (PIMAGEBUTTON)PVOIDFROMMP(mp1)) )
  1917.        return(MRFROMLONG(TRUE));
  1918.  
  1919.        LoadBitmaps((PIMAGEBUTTON)PVOIDFROMMP(mp1),
  1920.            (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP),
  1921.            (HMODULE)LONGFROMMP(mp2));
  1922.        WinQueryWindowRect(hWnd,    &rcl);
  1923.  
  1924.        SizeButton(hWnd,    rcl.xLeft, rcl.yBottom,
  1925.           (rcl.xRight -    rcl.xLeft),
  1926.           (rcl.yTop   -    rcl.yBottom));
  1927.        break;
  1928.  
  1929.    /*********************************************************************/
  1930.    /*  Control Defined Message:     Reset state                */
  1931.    /*********************************************************************/
  1932.  
  1933.    case    IM_RESETBTN :
  1934.                /* Get the address of the control info from the    */
  1935.                /* control's reserved memory                     */
  1936.  
  1937.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1938.  
  1939.        if ( pimgbtn->flState & IBS_DISABLED )
  1940.        pimgbtn->flState = IBS_DISABLED;
  1941.        else
  1942.        pimgbtn->flState = 0;
  1943.  
  1944.        WinInvalidateRect(hWnd, NULL, FALSE);
  1945.        break;
  1946.  
  1947.    /*********************************************************************/
  1948.    /*  Control Defined Message:     Reset state                */
  1949.    /*********************************************************************/
  1950.  
  1951.    case    IM_SELECTBTN :
  1952.                /* Get the address of the control info from the    */
  1953.                /* control's reserved memory                     */
  1954.  
  1955.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1956.  
  1957.        if ( pimgbtn->flState & IBS_DISABLED )
  1958.        pimgbtn->flState = IBS_DISABLED | SHORT1FROMMP(mp1);
  1959.        else
  1960.        pimgbtn->flState = SHORT1FROMMP(mp1);
  1961.  
  1962.        WinInvalidateRect(hWnd, NULL, FALSE);
  1963.        break;
  1964.  
  1965.    /*********************************************************************/
  1966.    /*  Control Defined Message:     Button    click simulation        */
  1967.    /*********************************************************************/
  1968.  
  1969.    case    IM_BTNCLK :
  1970.                /* Get the address of the control info from the    */
  1971.                /* control's reserved memory                     */
  1972.  
  1973.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  1974.  
  1975.        if ( pimgbtn->flState & IBS_DISABLED )
  1976.        return(0L);
  1977.        else
  1978.        {
  1979.        if (    pimgbtn->flState & IBS_SET )
  1980.            pimgbtn->flState    = IBS_UP;
  1981.        else
  1982.            pimgbtn->flState    = IBS_SET;
  1983.  
  1984.        WinSendMsg(pimgbtn->hwndOwner, WM_CONTROL,
  1985.               MPFROM2SHORT(pimgbtn->id,    IBN_SELECT),
  1986.               MPFROMSHORT(pimgbtn->flState & IBS_SET ? TRUE : FALSE));
  1987.  
  1988.                /* Invalidate the button    image to update    it from    */
  1989.                /* down position                    */
  1990.  
  1991.        WinInvalidateRect(hWnd, (PRECTL)NULL, TRUE);
  1992.        }
  1993.        break;
  1994.  
  1995.    /*********************************************************************/
  1996.    /*  Control Defined Message:     Set Bitmap image            */
  1997.    /*********************************************************************/
  1998.  
  1999.    case    IM_SETBITMAP :
  2000.                /* Get the address of the control info from the    */
  2001.                /* control's reserved memory                     */
  2002.  
  2003.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2004.  
  2005.        switch (    LONGFROMMP(mp1)    )
  2006.        {
  2007.        case    IBP_UP :
  2008.            if ( pimgbtn->hbm )
  2009.            GpiDeleteBitmap(pimgbtn->hbm);
  2010.  
  2011.            pimgbtn->hbm = (HBITMAP)LONGFROMMP(mp2);
  2012.            GpiQueryBitmapParameters(pimgbtn->hbm, &bmpi);
  2013.            pimgbtn->cx = bmpi.cx;
  2014.            pimgbtn->cy = bmpi.cy;
  2015.            break;
  2016.  
  2017.        case    IBP_DOWN :
  2018.            if ( pimgbtn->hbmDown )
  2019.            GpiDeleteBitmap(pimgbtn->hbmDown);
  2020.  
  2021.            pimgbtn->hbmDown    = (HBITMAP)LONGFROMMP(mp2);
  2022.            GpiQueryBitmapParameters(pimgbtn->hbmDown, &bmpi);
  2023.            pimgbtn->cxDown = bmpi.cx;
  2024.            pimgbtn->cyDown = bmpi.cy;
  2025.            break;
  2026.  
  2027.        case    IBP_DISABLED :
  2028.            if ( pimgbtn->hbmDisabled )
  2029.            GpiDeleteBitmap(pimgbtn->hbmDisabled);
  2030.  
  2031.            pimgbtn->hbmDisabled = (HBITMAP)LONGFROMMP(mp2);
  2032.            GpiQueryBitmapParameters(pimgbtn->hbmDisabled, &bmpi);
  2033.            pimgbtn->cxDisabled = bmpi.cx;
  2034.            pimgbtn->cyDisabled = bmpi.cy;
  2035.            break;
  2036.  
  2037.        default :
  2038.            return(MRFROMLONG(TRUE));
  2039.        }
  2040.  
  2041.  
  2042.        SizeButton(hWnd,    rcl.xLeft, rcl.yBottom,
  2043.           (rcl.xRight -    rcl.xLeft),
  2044.           (rcl.yTop   -    rcl.yBottom));
  2045.        break;
  2046.  
  2047. /************************************************************************/
  2048. /************************************************************************/
  2049. /*                                    */
  2050. /* Part    8: Control destruction coding                    */
  2051. /*                                    */
  2052. /************************************************************************/
  2053. /************************************************************************/
  2054.  
  2055.    /*********************************************************************/
  2056.    /*  Window being destroyed, perform clean-up                */
  2057.    /*********************************************************************/
  2058.  
  2059.    case    WM_DESTROY :
  2060.                /* Get the address of the control info from the    */
  2061.                /* control's reserved memory                     */
  2062.  
  2063.        pimgbtn = (PIMGBTN)WinQueryWindowPtr(hWnd, QUCWP_WNDP);
  2064.  
  2065.                /* Delete the bitmap images of the buttons    */
  2066.  
  2067.        GpiDeleteBitmap(pimgbtn->hbm);
  2068.        GpiDeleteBitmap(pimgbtn->hbmDown);
  2069.        GpiDeleteBitmap(pimgbtn->hbmDisabled);
  2070.  
  2071.                /* Release the memory allocated for use by the    */
  2072.                /* control                    */
  2073.  
  2074.        DosFreeMem((PVOID)pimgbtn);
  2075.        break;
  2076.                /* Default message processing            */
  2077.    default :
  2078.        return(WinDefWindowProc(hWnd, msg, mp1, mp2));
  2079.    }
  2080. return(0L);
  2081. }
  2082.