home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / video / vidcap / toolbar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-05  |  55.2 KB  |  1,738 lines

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. /****************************************************************************
  12.  *
  13.  *   toolbar.c: Toolbar control window
  14.  *
  15.  *   Vidcap32 Source code
  16.  *
  17.  ***************************************************************************/
  18.  
  19. #include <string.h>
  20.  
  21. #include <windows.h>
  22. #include <windowsx.h>
  23. //#include <win32.h>
  24. #include "toolbar.h"        // use this for generic app
  25. /************************************************************************/
  26.  
  27. /* work for win3.0 */
  28. #ifndef COLOR_BTNHIGHLIGHT
  29. #define COLOR_BTNHIGHLIGHT 20
  30. #endif
  31.  
  32. char    szToolBarClass[] = "ToolBarClass";
  33. HBRUSH    ghbrToolbar;        // brush for toolbar background
  34.  
  35. //
  36. // Window proc for buttons, THIS FUNCTION MUST BE EXPORTED
  37. //
  38. LONG FAR PASCAL toolbarWndProc(HWND, unsigned, UINT, LONG);
  39.  
  40. typedef long (FAR PASCAL *LPWNDPROC)();
  41.  
  42. /*
  43.     Defines
  44. */
  45.  
  46. #ifdef _WIN32
  47.  
  48. #define GETARRAYBUTT(hwnd)    ((HANDLE)GetWindowLong(hwnd,GWL_ARRAYBUTT))
  49. #define GETNUMBUTTONS(hwnd)    ((int)GetWindowLong(hwnd,GWL_NUMBUTTONS))
  50. #define GETPRESSED(hwnd)    ((BOOL)GetWindowLong(hwnd,GWL_PRESSED))
  51. #define GETKEYPRESSED(hwnd)    ((BOOL)GetWindowLong(hwnd,GWL_KEYPRESSED))
  52. #define GETWHICH(hwnd)        ((int)GetWindowLong(hwnd,GWL_WHICH))
  53. #define GETSHIFTED(hwnd)    ((BOOL)GetWindowLong(hwnd,GWL_SHIFTED))
  54. #define GETBMPHANDLE(hwnd)    ((HANDLE)GetWindowLong(hwnd,GWL_BMPHANDLE))
  55. #define GETBMPINT(hwnd)        ((int)GetWindowLong(hwnd,GWL_BMPINT))
  56. #define GETBUTTONSIZE(hwnd)    GetWindowLong(hwnd,GWL_BUTTONSIZE)
  57. #define GETHINST(hwnd)        ((HANDLE)GetWindowLong(hwnd,GWL_HINST))
  58.  
  59.  
  60. #define SETARRAYBUTT(hwnd, h) SetWindowLong(hwnd, GWL_ARRAYBUTT, (UINT)h)
  61. #define SETNUMBUTTONS(hwnd, wNumButtons) \
  62.             SetWindowLong(hwnd, GWL_NUMBUTTONS, wNumButtons)
  63. #define SETPRESSED(hwnd, f)    SetWindowLong(hwnd, GWL_PRESSED, (UINT)f)
  64. #define SETKEYPRESSED(hwnd, f)    SetWindowLong(hwnd, GWL_KEYPRESSED, (UINT)f)
  65. #define SETWHICH(hwnd, i)    SetWindowLong(hwnd, GWL_WHICH, (UINT)i)
  66. #define SETSHIFTED(hwnd, i)    SetWindowLong(hwnd, GWL_SHIFTED, (UINT)i)
  67. #define SETBMPHANDLE(hwnd, h)    SetWindowLong(hwnd, GWL_BMPHANDLE, (UINT)h)
  68. #define SETBMPINT(hwnd, i)    SetWindowLong(hwnd, GWL_BMPINT, (UINT)i)
  69. #define SETBUTTONSIZE(hwnd, l)    SetWindowLong(hwnd, GWL_BUTTONSIZE, l)
  70. #define SETHINST(hwnd, h)    SetWindowLong(hwnd, GWL_HINST, (UINT)h)
  71.  
  72. #else
  73.  
  74. #define GETARRAYBUTT(hwnd)    ((HANDLE)GetWindowWord(hwnd,GWW_ARRAYBUTT))
  75. #define GETNUMBUTTONS(hwnd)    ((int)GetWindowWord(hwnd,GWW_NUMBUTTONS))
  76. #define GETPRESSED(hwnd)    ((BOOL)GetWindowWord(hwnd,GWW_PRESSED))
  77. #define GETKEYPRESSED(hwnd)    ((BOOL)GetWindowWord(hwnd,GWW_KEYPRESSED))
  78. #define GETWHICH(hwnd)        ((int)GetWindowWord(hwnd,GWW_WHICH))
  79. #define GETSHIFTED(hwnd)    ((BOOL)GetWindowWord(hwnd,GWW_SHIFTED))
  80. #define GETBMPHANDLE(hwnd)    ((HANDLE)GetWindowWord(hwnd,GWW_BMPHANDLE))
  81. #define GETBMPINT(hwnd)        ((int)GetWindowWord(hwnd,GWW_BMPINT))
  82. #define GETBUTTONSIZE(hwnd)    GetWindowLong(hwnd,GWL_BUTTONSIZE)
  83. #define GETHINST(hwnd)        ((HANDLE)GetWindowWord(hwnd,GWW_HINST))
  84.  
  85.  
  86. #define SETARRAYBUTT(hwnd, h) SetWindowWord(hwnd, GWW_ARRAYBUTT, (WORD)h)
  87. #define SETNUMBUTTONS(hwnd, wNumButtons) \
  88.             SetWindowWord(hwnd, GWW_NUMBUTTONS, wNumButtons)
  89. #define SETPRESSED(hwnd, f)    SetWindowWord(hwnd, GWW_PRESSED, (WORD)f)
  90. #define SETKEYPRESSED(hwnd, f)    SetWindowWord(hwnd, GWW_KEYPRESSED, (WORD)f)
  91. #define SETWHICH(hwnd, i)    SetWindowWord(hwnd, GWW_WHICH, (WORD)i)
  92. #define SETSHIFTED(hwnd, i)    SetWindowWord(hwnd, GWW_SHIFTED, (WORD)i)
  93. #define SETBMPHANDLE(hwnd, h)    SetWindowWord(hwnd, GWW_BMPHANDLE, (WORD)h)
  94. #define SETBMPINT(hwnd, i)    SetWindowWord(hwnd, GWW_BMPINT, (WORD)i)
  95. #define SETBUTTONSIZE(hwnd, l)    SetWindowLong(hwnd, GWL_BUTTONSIZE, l)
  96. #define SETHINST(hwnd, h)    SetWindowWord(hwnd, GWW_HINST, (WORD)h)
  97.  
  98. #endif
  99.  
  100. #define lpCreate ((LPCREATESTRUCT)lParam)
  101.  
  102. /* Prototypes */
  103.  
  104. static void NEAR PASCAL NotifyParent(HWND, int);
  105.  
  106.  
  107.  
  108. /**************************************************************************
  109.     toolbarInit( hInst, hPrev )
  110.  
  111.     Call this routine to initialize the toolbar code.
  112.  
  113.     Arguments:
  114.         hPrev    instance handle of previous instance
  115.         hInst    instance handle of current instance
  116.  
  117.     Returns:
  118.         TRUE if successful, FALSE if not
  119. ***************************************************************************/
  120.  
  121. BOOL FAR PASCAL toolbarInit(HANDLE hInst, HANDLE hPrev)
  122. {
  123.     WNDCLASS    cls;
  124.     
  125.     /* Register the tool bar window class */
  126.     if (!hPrev) {
  127.  
  128.         cls.hCursor        = LoadCursor(NULL,IDC_ARROW);
  129.         cls.hIcon          = NULL;
  130.         cls.lpszMenuName   = NULL;
  131.         cls.lpszClassName  = (LPSTR)szToolBarClass;
  132.         cls.hbrBackground  = (HBRUSH)(COLOR_BTNFACE + 1);
  133.         cls.hInstance      = hInst;
  134.         cls.style          = CS_DBLCLKS;
  135.         cls.lpfnWndProc    = toolbarWndProc;
  136.         cls.cbClsExtra     = 0;
  137.         cls.cbWndExtra     = TOOLBAR_EXTRABYTES;
  138.         if (!RegisterClass(&cls))
  139.         return FALSE;
  140.     }
  141.  
  142.     return TRUE;
  143. }
  144.  
  145.  
  146. /***************************************************************************/
  147. /* toolbarSetBitmap:  takes a resource ID and associates that bitmap with  */
  148. /*                    a given toolbar.  Also takes the instance handle and */
  149. /*                    the size of the buttons on the toolbar.              */
  150. /***************************************************************************/
  151. BOOL FAR PASCAL toolbarSetBitmap(HWND hwnd, HANDLE hInst, int ibmp, POINT ptSize)
  152. {
  153.     SETHINST(hwnd, hInst);
  154.     SETBMPHANDLE(hwnd, NULL);
  155.     SETBMPINT(hwnd, ibmp);
  156.     SETBUTTONSIZE(hwnd, MAKELONG(ptSize.y, ptSize.x));
  157.     return (BOOL)SendMessage(hwnd, WM_SYSCOLORCHANGE, 0, 0L); // do the work
  158. }
  159.  
  160. /***************************************************************************/
  161. /* toolbarGetNumButtons:  return the number of buttons registered on a     */
  162. /*                        given toolbar window.                            */
  163. /***************************************************************************/
  164. int FAR PASCAL toolbarGetNumButtons(HWND hwnd)
  165. {
  166.     return GETNUMBUTTONS(hwnd);
  167. }
  168.  
  169.  
  170. /***************************************************************************/
  171. /* toolbarButtonFromIndex:  Given an index into the array of buttons on    */
  172. /*                          this toolbar, return which button is there.    */
  173. /*                          Returns -1 for an error code.                  */
  174. /***************************************************************************/
  175. int FAR PASCAL toolbarButtonFromIndex(HWND hwnd, int iBtnPos)
  176. {
  177.     int        iButton;
  178.     HANDLE        h;
  179.     TOOLBUTTON    far *lpaButtons;
  180.  
  181.     /* Get the array of buttons on this toolbar */
  182.     h = GETARRAYBUTT(hwnd);
  183.     if (!h)
  184.         return -1;
  185.     
  186.     /* Validate the index passed in */
  187.     if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0)
  188.         return -1;
  189.  
  190.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  191.  
  192.     /* Read off the answer */
  193.     iButton = lpaButtons[iBtnPos].iButton;
  194.  
  195.     GlobalUnlock(h);
  196.     return iButton;
  197. }
  198.  
  199.  
  200. /***************************************************************************/
  201. /* toolbarIndexFromButton:  Given a button ID, return the position in the  */
  202. /*                          array that it appears at.                      */
  203. /*                          Returns -1 for an error code.                  */
  204. /***************************************************************************/
  205. int FAR PASCAL toolbarIndexFromButton(HWND hwnd, int iButton)
  206. {
  207.     int        i, iBtnPos = -1;
  208.     HANDLE        h;
  209.     TOOLBUTTON    far *lpButton;
  210.  
  211.     /* Get the array of buttons */
  212.     h = GETARRAYBUTT(hwnd);
  213.     if (!h)
  214.         return -1;
  215.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  216.  
  217.     /* loop through until you find it */
  218.     for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  219.         if (lpButton->iButton == iButton) {
  220.             iBtnPos = i;
  221.             break;
  222.         }
  223.  
  224.     GlobalUnlock(h);
  225.     return iBtnPos;
  226. }
  227.  
  228.  
  229.  
  230. /***************************************************************************/
  231. /* toolbarPrevStateFromButton:  Given a button ID, return the state that   */
  232. /*                              the button was in before it was pressed    */
  233. /*                              all the way down (for non-push buttons).   */
  234. /*                              Return -1 for an error code.               */
  235. /***************************************************************************/
  236. int FAR PASCAL toolbarPrevStateFromButton(HWND hwnd, int iButton)
  237. {
  238.     int        i, iPrevState = -1;
  239.     HANDLE        h;
  240.     TOOLBUTTON    far *lpButton;
  241.  
  242.     /* Get the array of buttons */
  243.     h = GETARRAYBUTT(hwnd);
  244.     if (!h)
  245.         return -1;
  246.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  247.  
  248.     /* look for what we need */
  249.     for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  250.         if (lpButton->iButton == iButton) {
  251.             iPrevState = lpButton->iPrevState;
  252.             break;
  253.         }
  254.  
  255.     GlobalUnlock(h);
  256.     return iPrevState;
  257. }
  258.  
  259.  
  260.  
  261. /***************************************************************************/
  262. /* toolbarActivityFromButton:   Given a button ID, return the most recent  */
  263. /*                              activity that happened to it. (eg DBLCLK)  */
  264. /*                              Return -1 for an error code.               */
  265. /***************************************************************************/
  266. int FAR PASCAL toolbarActivityFromButton(HWND hwnd, int iButton)
  267. {
  268.     int        i, iActivity = -1;
  269.     HANDLE        h;
  270.     TOOLBUTTON    far *lpButton;
  271.  
  272.     /* Get the array of buttons */
  273.     h = GETARRAYBUTT(hwnd);
  274.     if (!h)
  275.         return -1;
  276.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  277.  
  278.     /* loop through until you find it */
  279.     for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  280.         if (lpButton->iButton == iButton)
  281.             iActivity = lpButton->iActivity;
  282.  
  283.     GlobalUnlock(h);
  284.     return iActivity;
  285. }
  286.  
  287.  
  288.  
  289. /***************************************************************************/
  290. /* toolbarIndexFromPoint:  Given a point in the toolbar window, return the */
  291. /*                         index of the button beneath that point.         */
  292. /*                         Return -1 for an error code.                    */
  293. /***************************************************************************/
  294. int FAR PASCAL toolbarIndexFromPoint(HWND hwnd, POINT pt)
  295. {
  296.     int        i, iBtnPos = -1;
  297.     HANDLE        h;
  298.     TOOLBUTTON    far *lpButton;
  299.  
  300.     /* Get the array of buttons */
  301.     h = GETARRAYBUTT(hwnd);
  302.     if (!h)
  303.         return -1;
  304.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  305.  
  306.     /* loop through until we find an intersection */
  307.     for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  308.         if (PtInRect(&lpButton->rc, pt)) {
  309.             iBtnPos = i;
  310.             break;
  311.         }
  312.  
  313.     GlobalUnlock(h);
  314.     return iBtnPos;
  315. }
  316.  
  317.  
  318.  
  319. /***************************************************************************/
  320. /* toolbarRectFromIndex:   Given an index into our array of buttons, return*/
  321. /*                         the rect occupied by that button.               */
  322. /*                         Return a NULL rect for an error.                */
  323. /***************************************************************************/
  324. BOOL FAR PASCAL toolbarRectFromIndex(HWND hwnd, int iBtnPos, LPRECT lprc)
  325. {
  326.     HANDLE        h;
  327.     TOOLBUTTON    far *lpaButtons;
  328.     
  329.     /* Get the array of buttons */
  330.     h = GETARRAYBUTT(hwnd);
  331.     if (!h)
  332.         return FALSE;
  333.  
  334.     /* Validate the index passed in */
  335.     if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0)
  336.         return FALSE;
  337.  
  338.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  339.  
  340.     /* Read off the rect */
  341.     *lprc = lpaButtons[iBtnPos].rc;
  342.  
  343.     GlobalUnlock(h);
  344.         return TRUE;
  345. }
  346.  
  347.  
  348.  
  349. /***************************************************************************/
  350. /* toolbarFullStateFromButton: Given a button in our array of buttons,     */
  351. /*                             return the state of that button.            */
  352. /*                             (including the wierd state FULLDOWN). For   */
  353. /*                             just UP or DOWN or GRAYED,                  */
  354. /*                             call toolbarStateFromButton.           */
  355. /*                             Return -1 for an error.                     */
  356. /***************************************************************************/
  357. int FAR PASCAL toolbarFullStateFromButton(HWND hwnd, int iButton)
  358. {
  359.     int        iState, iBtnPos;
  360.     HANDLE        h;
  361.     TOOLBUTTON    far *lpaButtons;
  362.  
  363.     iBtnPos = toolbarIndexFromButton(hwnd, iButton);
  364.     if (iBtnPos == -1)
  365.         return -1;
  366.  
  367.     /* Get the array of buttons */
  368.     h = GETARRAYBUTT(hwnd);
  369.     if (!h)
  370.         return -1;
  371.  
  372.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  373.  
  374.     /* Read off the state */
  375.     iState = lpaButtons[iBtnPos].iState;
  376.  
  377.     GlobalUnlock(h);
  378.     return iState;
  379. }    
  380.  
  381.  
  382.  
  383. /***************************************************************************/
  384. /* toolbarStateFromButton: This fn is called by the parent application     */
  385. /*                         to get the state of a button.  It will only     */
  386. /*                         return DOWN, or UP or GRAYED as opposed to      */
  387. /*                         toolbarFullStateFromButton which could return   */
  388. /*                         FULLDOWN.                                       */
  389. /***************************************************************************/
  390. int FAR PASCAL toolbarStateFromButton(HWND hwnd, int iButton)
  391. {
  392.     int    iState;
  393.  
  394.     /* If a checkbox button is all the way down, it's previous state is */
  395.     /* the one we want.                            */
  396.     if ((iState = toolbarFullStateFromButton(hwnd, iButton))
  397.                             == BTNST_FULLDOWN) {
  398.         iState = toolbarPrevStateFromButton(hwnd, iButton);
  399.         return iState;
  400.     } else
  401.         return iState;
  402. }
  403.  
  404.  
  405.  
  406. /***************************************************************************/
  407. /* toolbarStringFromIndex: Given an index into our array of buttons, return*/
  408. /*                         the string resource associated with it.         */
  409. /*                         Return -1 for an error.                         */
  410. /***************************************************************************/
  411. int FAR PASCAL toolbarStringFromIndex(HWND hwnd, int iBtnPos)
  412. {
  413.     int        iString;
  414.     HANDLE        h;
  415.     TOOLBUTTON    far *lpaButtons;
  416.  
  417.     /* Get the array of buttons */
  418.     h = GETARRAYBUTT(hwnd);
  419.     if (!h)
  420.         return -1;
  421.  
  422.     /* Validate the index passed in */
  423.     if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0)
  424.         return -1;
  425.  
  426.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  427.  
  428.     /* Read off the ID */
  429.     iString = lpaButtons[iBtnPos].iString;    
  430.  
  431.     GlobalUnlock(h);
  432.     return iString;
  433. }
  434.  
  435.  
  436.  
  437. /***************************************************************************/
  438. /* toolbarTypeFromIndex:   Given an index into our array of buttons, return*/
  439. /*                         the type of button it is (PUSH, RADIO, etc.)    */
  440. /*                         Return -1 for an error.                         */
  441. /***************************************************************************/
  442. int FAR PASCAL toolbarTypeFromIndex(HWND hwnd, int iBtnPos)
  443. {
  444.     int        iType;
  445.     HANDLE        h;
  446.     TOOLBUTTON    far *lpaButtons;
  447.  
  448.     /* Get the Array of buttons */
  449.     h = GETARRAYBUTT(hwnd);
  450.     if (!h)
  451.         return -1;
  452.  
  453.     /* Validate the index passed in */
  454.     if (iBtnPos > GETNUMBUTTONS(hwnd) || iBtnPos < 0)
  455.         return -1;
  456.  
  457.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  458.  
  459.     /* Read off the type */
  460.     iType = lpaButtons[iBtnPos].iType;
  461.  
  462.     GlobalUnlock(h);
  463.     return iType;
  464. }
  465.  
  466.  
  467. /***************************************************************************/
  468. /* toolbarAddTool:  Add a button to this toolbar.  Sort them by leftmost   */
  469. /*                  position in the window (for tabbing order).            */
  470. /*                  Return FALSE for an error.                             */
  471. /***************************************************************************/
  472. BOOL FAR PASCAL toolbarAddTool(HWND hwnd, TOOLBUTTON tb)
  473. {
  474.     HANDLE        h;
  475.     TOOLBUTTON far  *lpaButtons;
  476.     int        cButtons, i, j;
  477.     BOOL        fInsert = FALSE;
  478.  
  479.     /* We better not have this button on the toolbar already */
  480.     if (toolbarIndexFromButton(hwnd, tb.iButton) != -1)
  481.         return FALSE;
  482.  
  483.     /* Get the array of buttons */
  484.     h = GETARRAYBUTT(hwnd);
  485.     if (!h)
  486.         return FALSE;
  487.  
  488.     /* How many buttons are there already? */
  489.     cButtons = GETNUMBUTTONS(hwnd);
  490.  
  491.     /* If we have filled our alloced memory for this array already, we */
  492.     /* need to re-alloc some more memory                   */
  493.     if ( ((cButtons & (TOOLGROW - 1)) == 0) && (cButtons > 0) ) {
  494.  
  495.         /* Re-alloc it bigger */
  496.         h = GlobalReAlloc(h,
  497.             GlobalSize(h) + TOOLGROW * sizeof(TOOLBUTTON),
  498.             GMEM_MOVEABLE | GMEM_SHARE);
  499.         if (!h)
  500.             return FALSE;
  501.     }
  502.  
  503.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  504.  
  505.     /* Look for the spot we need to insert this new guy at.    */
  506.      /* Remember, we sort by left x position    breaking ties   */
  507.      /* with top y position.                    */
  508.     for (i = 0; i < cButtons; i++) {
  509.                         // Here it goes
  510.          if (lpaButtons[i].rc.left > tb.rc.left ||
  511.              (lpaButtons[i].rc.left == tb.rc.left &&
  512.                  lpaButtons[i].rc.top > tb.rc.top)) {
  513.         fInsert = TRUE;
  514.         /* Open up a spot in the array */
  515.         for (j = cButtons; j > i; j--)
  516.             lpaButtons[j] = lpaButtons[j-1];
  517.         /* Add our new guy */
  518.         lpaButtons[i] = tb;        // redraw now
  519.         InvalidateRect(hwnd, &(lpaButtons[i].rc), FALSE);
  520.         break;
  521.         }
  522.     }
  523.  
  524.     /* If our loop didn't insert it, we need to add it to the end */
  525.     if (!fInsert)
  526.         lpaButtons[i] = tb;
  527.  
  528.     /* If we are told that this button has the focus, we better    */
  529.     /* change the focus to it.  Then use the normal state.          */
  530.     if (tb.iState == BTNST_FOCUSUP) {
  531.         tb.iState = BTNST_UP;
  532.         SETWHICH(hwnd, i);
  533.     } else if (tb.iState == BTNST_FOCUSDOWN || tb.iState == BTNST_FULLDOWN){
  534.         tb.iState = BTNST_DOWN;    // nonsense to init to FULLDOWN
  535.         SETWHICH(hwnd, i);
  536.     }
  537.  
  538.     cButtons++;        // one more button now.
  539.     GlobalUnlock(h);
  540.  
  541.     SETNUMBUTTONS(hwnd, cButtons);    // new count
  542.     SETARRAYBUTT(hwnd, h);        // re-alloc might have changed it
  543.  
  544.     /* Just in case no one else makes this new button draw */
  545.     InvalidateRect(hwnd, &(tb.rc), FALSE);
  546.  
  547.     return TRUE;
  548. }
  549.  
  550.  
  551.  /***************************************************************************/
  552.  /* toolbarRetrieveTool:  Get the TOOLBUTTON struct for the given button.   */
  553.  /*                       Return FALSE for an error.                        */
  554.  /***************************************************************************/
  555.  BOOL FAR PASCAL toolbarRetrieveTool(HWND hwnd, int iButton, LPTOOLBUTTON lptb)
  556.  {
  557.      int        i;
  558.      HANDLE        h;
  559.      TOOLBUTTON    far *lpButton;
  560.      BOOL        fFound = FALSE;
  561.      
  562.      /* Get the array of buttons */
  563.      h = GETARRAYBUTT(hwnd);
  564.      if (!h)
  565.          return FALSE;
  566.      lpButton = (TOOLBUTTON far *)GlobalLock(h);
  567.  
  568.      /* look for what we need */
  569.      for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  570.          if (lpButton->iButton == iButton) {
  571.              *lptb = *lpButton;
  572.              fFound = TRUE;
  573.              break;
  574.          }
  575.  
  576.      GlobalUnlock(h);
  577.      return fFound;
  578.  }
  579.  
  580.  
  581.  
  582. /***************************************************************************/
  583. /* toolbarRemoveTool:  Remove this button ID from our array of buttons on  */
  584. /*                    the toolbar.  (only 1 of each button ID allowed).   */
  585. /*                     Return FALSE for an error.                          */
  586. /***************************************************************************/
  587. BOOL FAR PASCAL toolbarRemoveTool(HWND hwnd, int iButton)
  588. {
  589.     HANDLE        h;
  590.     TOOLBUTTON far  *lpaButtons;
  591.     int        cButtons, i, j;
  592.     BOOL        fFound = FALSE;
  593.  
  594.     /* Get the array of buttons */
  595.     h = GETARRAYBUTT(hwnd);
  596.     if (!h)
  597.         return FALSE;
  598.  
  599.     /* How many buttons are on there now? */
  600.     cButtons = GETNUMBUTTONS(hwnd);
  601.  
  602.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  603.  
  604.     /* Find a match, remove it, and close the array around it. */
  605.     for (i = 0; i < cButtons; i++)
  606.         if (lpaButtons[i].iButton == iButton) {    
  607.             fFound = TRUE;
  608.                         // redraw now
  609.             InvalidateRect(hwnd, &(lpaButtons[i].rc), FALSE);
  610.             if (i != cButtons - 1)    // Last button? Don't bother!
  611.                 for (j = i; j < cButtons; j++)
  612.                     lpaButtons[j] = lpaButtons[j + 1];
  613.             break;
  614.         }
  615.  
  616.     GlobalUnlock(h);
  617.  
  618.     /* Didn't find it! */
  619.     if (!fFound)
  620.         return FALSE;
  621.  
  622.     /* One less button */
  623.     cButtons--;
  624.  
  625.     /* Every once in a while, re-alloc a smaller array chunk to    */
  626.     /* save memory.                            */
  627.     if ( ((cButtons & (TOOLGROW - 1)) == 0) && (cButtons > 0) ) {
  628.  
  629.         /* Re-alloc it smaller */
  630.         h = GlobalReAlloc(h,
  631.             GlobalSize(h) - TOOLGROW * sizeof(TOOLBUTTON),
  632.             GMEM_MOVEABLE | GMEM_SHARE);
  633.         if (!h)
  634.             return FALSE;
  635.     }
  636.  
  637.     SETNUMBUTTONS(hwnd, cButtons);    // new count
  638.     SETARRAYBUTT(hwnd, h);        // re-alloc could have changed it
  639.  
  640.     return TRUE;
  641. }
  642.  
  643. /***************************************************************************/
  644. /* toolbarModifyString: Given a button ID on the toolbar, change it's      */
  645. /*                      string resource associated with it.                */
  646. /*                      returns FALSE for an error or if no such button    */
  647. /***************************************************************************/
  648. BOOL FAR PASCAL toolbarModifyString(HWND hwnd, int iButton, int iString)
  649. {
  650.     HANDLE        h;
  651.     TOOLBUTTON far  *lpButton;
  652.     int        cButtons, i;
  653.     BOOL        fFound = FALSE;
  654.  
  655.     /* Get the array of buttons */
  656.     h = GETARRAYBUTT(hwnd);
  657.     if (!h)
  658.         return FALSE;
  659.  
  660.     /* How many buttons? */
  661.     cButtons = GETNUMBUTTONS(hwnd);
  662.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  663.  
  664.     /* Find that button, and change it's state */
  665.     for (i = 0; i < cButtons; i++, lpButton++)
  666.         if (lpButton->iButton == iButton) {
  667.             lpButton->iString = iString;
  668.             fFound = TRUE;            // redraw now
  669.             break;
  670.         }
  671.  
  672.     GlobalUnlock(h);
  673.     return fFound;
  674. }
  675.  
  676. /***************************************************************************/
  677. /* toolbarModifyState:  Given a button ID on the toolbar, change it's      */
  678. /*                      state.                                             */
  679. /*                      returns FALSE for an error or if no such button    */
  680. /***************************************************************************/
  681. BOOL FAR PASCAL toolbarModifyState(HWND hwnd, int iButton, int iState)
  682. {
  683.     HANDLE        h;
  684.     TOOLBUTTON far  *lpButton;
  685.     int        cButtons, i;
  686.     BOOL        fFound = FALSE;
  687.  
  688.     /* Get the array of buttons */
  689.     h = GETARRAYBUTT(hwnd);
  690.     if (!h)
  691.         return FALSE;
  692.  
  693.     /* How many buttons? */
  694.     cButtons = GETNUMBUTTONS(hwnd);
  695.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  696.  
  697.     /* Find that button, and change it's state */
  698.     for (i = 0; i < cButtons; i++, lpButton++)
  699.         if (lpButton->iButton == iButton) {
  700.             if (lpButton->iState != iState) {
  701.                 lpButton->iState = iState;
  702.                 InvalidateRect(hwnd, &(lpButton->rc), FALSE);
  703.             }
  704.             fFound = TRUE;            // redraw now
  705.  
  706.             /* if we're pushing a radio button down, bring */
  707.             /* all others in its group up */
  708.             if (lpButton->iType >= BTNTYPE_RADIO &&
  709.                     iState == BTNST_DOWN)
  710.                 toolbarExclusiveRadio(hwnd, lpButton->iType,
  711.                                 iButton);
  712.             break;
  713.         }
  714.  
  715.     GlobalUnlock(h);
  716.     return fFound;
  717. }
  718.  
  719.  
  720. /***************************************************************************/
  721. /* toolbarModifyPrevState: Given a button on the toolbar, change it's prev-*/
  722. /*                      ious state. Used for non-PUSH buttons to remember  */
  723. /*                      what state a button was in before pressed all the  */
  724. /*                      way down, so that when you let go, you know what   */
  725. /*                      state to set it to (the opposite of what it was).  */
  726. /*                      returns FALSE for an error (no button array)       */
  727. /***************************************************************************/
  728. BOOL FAR PASCAL toolbarModifyPrevState(HWND hwnd, int iButton, int iPrevState)
  729. {
  730.     HANDLE        h;
  731.     TOOLBUTTON far  *lpButton;
  732.     int        cButtons, i;
  733.  
  734.     /* Get button array */
  735.     h = GETARRAYBUTT(hwnd);
  736.     if (!h)
  737.         return FALSE;
  738.  
  739.     /* How many buttons? */
  740.     cButtons = GETNUMBUTTONS(hwnd);
  741.  
  742.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  743.  
  744.     /* Find the button, change the state */
  745.     for (i = 0; i < cButtons; i++, lpButton++)
  746.         if (lpButton->iButton == iButton) {
  747.             lpButton->iPrevState = iPrevState;
  748.             break;
  749.         }
  750.  
  751.     GlobalUnlock(h);
  752.     return TRUE;
  753. }
  754.  
  755.  
  756. /***************************************************************************/
  757. /* toolbarModifyActivity: Given a button ID on the toolbar, change it's    */
  758. /*                        activity.  This tells the app what just happened */
  759. /*                        to the button (ie. KEYUP, MOUSEDBLCLK, etc.)     */
  760. /*                        returns FALSE for an error or if no such button  */
  761. /***************************************************************************/
  762. BOOL FAR PASCAL toolbarModifyActivity(HWND hwnd, int iButton, int iActivity)
  763. {
  764.     HANDLE        h;
  765.     TOOLBUTTON far  *lpButton;
  766.     int        cButtons, i;
  767.  
  768.     /* Get the button array */
  769.     h = GETARRAYBUTT(hwnd);
  770.     if (!h)
  771.         return FALSE;
  772.  
  773.     /* How many buttons */
  774.     cButtons = GETNUMBUTTONS(hwnd);
  775.  
  776.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  777.  
  778.     /* loop through and change the right one */
  779.     for (i = 0; i < cButtons; i++, lpButton++)
  780.         if (lpButton->iButton == iButton) {
  781.             lpButton->iActivity = iActivity;
  782.             break;
  783.         }
  784.  
  785.     GlobalUnlock(h);
  786.     return TRUE;
  787. }
  788.  
  789.  
  790.  
  791. /***************************************************************************/
  792. /* toolbarFixFocus:  SETWHICH() has been called to tell us which button    */
  793. /*                   has the focus, but the states of all the buttons are  */
  794. /*                   not updated (ie. take focus away from the old button) */
  795. /*                   This routine is called from the Paint routine to fix  */
  796. /*                   the states of all the buttons before drawing them.    */
  797. /*                   Returns FALSE for an error.                           */
  798. /***************************************************************************/
  799. BOOL FAR PASCAL toolbarFixFocus(HWND hwnd)
  800. {
  801.     int        iFocus;
  802.     HANDLE        h;
  803.     TOOLBUTTON    far *lpaButtons;
  804.  
  805.     /* Get the array of buttons */
  806.     h = GETARRAYBUTT(hwnd);
  807.     if (!h)
  808.         return FALSE;
  809.     lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  810.  
  811.         /* if focus is on an illegal button, default to the first one */
  812.     iFocus = GETWHICH(hwnd);
  813.     if (iFocus < 0 || iFocus >= GETNUMBUTTONS(hwnd))
  814.         SETWHICH(hwnd, 0);
  815.  
  816.     /* First of all, make sure that the focus in not on a grayed button. */
  817.     /* if so, we advance focus.  If it runs out of buttons without       */
  818.     /* finding a non-gray one, we start back at the beginning and start  */
  819.     /* looking for a non-gray one from there.  If every button is grayed,*/
  820.     /* we leave no focus anywhere.                         */
  821.     if (lpaButtons[GETWHICH(hwnd)].iState == BTNST_GRAYED) {
  822.         if (!toolbarMoveFocus(hwnd, FALSE)) {
  823.         SETWHICH(hwnd, -1);
  824.         toolbarMoveFocus(hwnd, FALSE);
  825.         }
  826.     }
  827.  
  828.     GlobalUnlock(h);
  829.     return TRUE;
  830. }
  831.  
  832.  
  833.  
  834. /***************************************************************************/
  835. /* toolbarExclusiveRadio:  For radio buttons, we need to pop all others    */
  836. /*                         in the group up when one goes down.  Pass the   */
  837. /*                         button that is going down, and its group, and   */
  838. /*                         this routine will pop all others up.            */
  839. /*                         Returns FALSE for an error.                     */
  840. /***************************************************************************/
  841. BOOL FAR PASCAL toolbarExclusiveRadio(HWND hwnd, int iType, int iButton)
  842. {
  843.     int        i;
  844.     HANDLE        h;
  845.     TOOLBUTTON    far *lpButton;
  846.  
  847.     /* Get the array of buttons */
  848.     h = GETARRAYBUTT(hwnd);
  849.     if (!h)
  850.         return FALSE;
  851.     lpButton = (TOOLBUTTON far *)GlobalLock(h);
  852.  
  853.     /* all buttons with this type that aren't this button come up    */
  854.     /* if they are not grayed                    */
  855.     for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  856.         if (lpButton->iType == iType)
  857.         if (lpButton->iButton != iButton &&
  858.                 lpButton->iState != BTNST_GRAYED) {
  859.             toolbarModifyState(hwnd, lpButton->iButton,    BTNST_UP);
  860.         }
  861.  
  862.     GlobalUnlock(h);
  863.     return TRUE;
  864. }
  865.  
  866.  
  867. /*    NotifyParent()  of activity to a button  */
  868.  
  869. static void NEAR PASCAL NotifyParent(HWND hwnd, int iButton)
  870. {
  871. #ifdef _WIN32
  872.         PostMessage(
  873.             GetParent(hwnd),
  874.             WM_COMMAND,
  875.             GET_WM_COMMAND_MPS(GetWindowLong(hwnd, GWL_ID), hwnd, iButton));
  876. #else
  877.     PostMessage(GetParent(hwnd),WM_COMMAND,
  878.             GetWindowWord(hwnd,GWW_ID),MAKELONG(hwnd,iButton));
  879. #endif
  880. }
  881.  
  882.  
  883. /***************************************************************************/
  884. /* toolbarPaintControl:  Handles paint messages by blitting each bitmap    */
  885. /*                       that is on the toolbar to its rect.               */
  886. /*                       First, it fixes the states of the buttons to give */
  887. /*                       the focus to the proper button.                   */
  888. /*                       Returns FALSE for an error.                       */
  889. /***************************************************************************/
  890. static BOOL NEAR PASCAL toolbarPaintControl(HWND hwnd, HDC hdc)
  891. {
  892.     int        iBtnPos;    /* 0 to toolbarGetNumButtons inclusive    */
  893.     int        iButton;    /* 0 to NUMBUTTONS-1 inclusive        */
  894.     int        iState;        /* 0 to NUMSTATES-1 inclusive        */
  895.     HDC        hdcBtn;        /* DC onto button bitmap        */
  896.  
  897.     RECT    rcDest;
  898.     POINT    pt;
  899.     long    l;
  900.     HANDLE    hbm;
  901.  
  902.     /* Make a source HDC for the button pictures, and select the button */
  903.     /* bitmap into it.                            */
  904.     hdcBtn = CreateCompatibleDC(hdc);
  905.     if (!hdcBtn)
  906.     return FALSE;
  907.     hbm = GETBMPHANDLE(hwnd);
  908.     if (hbm) {
  909.     if (!SelectObject(hdcBtn, GETBMPHANDLE(hwnd))) {
  910.         DeleteDC(hdcBtn);
  911.         return FALSE;
  912.     }
  913.     }
  914.  
  915.     toolbarFixFocus(hwnd);    // set the focus field correctly
  916.  
  917.     /* Go through all buttons on the toolbar */
  918.     for (iBtnPos = 0; iBtnPos < toolbarGetNumButtons(hwnd); iBtnPos++) {
  919.  
  920.     iButton = toolbarButtonFromIndex(hwnd, iBtnPos);    // button
  921.     iState = toolbarFullStateFromButton(hwnd, iButton);    // state
  922.     toolbarRectFromIndex(hwnd, iBtnPos, &rcDest);        // Dest Rect
  923.     
  924.     /* If we have the focus, we should draw it that way */
  925.         if (GetFocus() == hwnd && GETWHICH(hwnd) == iBtnPos
  926.                         && iState == BTNST_UP)
  927.         iState = BTNST_FOCUSUP;
  928.         if (GetFocus() == hwnd && GETWHICH(hwnd) == iBtnPos
  929.                         && iState == BTNST_DOWN)
  930.         iState = BTNST_FOCUSDOWN;
  931.  
  932.     /* If we don't have the focus, we should take it away */
  933.         if ((GetFocus() != hwnd || GETWHICH(hwnd) != iBtnPos)
  934.                         && iState == BTNST_FOCUSUP)
  935.         iState = BTNST_UP;
  936.         if ((GetFocus() != hwnd || GETWHICH(hwnd) == iBtnPos)
  937.                         && iState == BTNST_FOCUSDOWN)
  938.         iState = BTNST_DOWN;
  939.  
  940.     /* The size of each button */
  941.     l = GETBUTTONSIZE(hwnd);
  942.     pt.x = HIWORD(l);
  943.     pt.y = LOWORD(l);
  944.  
  945.     /* Blit from the button picture to the toolbar window */
  946.     BitBlt(hdc, rcDest.left, rcDest.top,
  947.         rcDest.right - rcDest.left, rcDest.bottom - rcDest.top,
  948.         hdcBtn, pt.x * iButton, pt.y * iState,
  949.         SRCCOPY);
  950.     }
  951.  
  952.     DeleteDC(hdcBtn);
  953.  
  954.     return TRUE;
  955. }
  956.  
  957.  
  958.  
  959.  
  960. /***************************************************************************/
  961. /* toolbarMoveFocus:  Move Focus forward or backward one button.  You give */
  962. /*                    it the direction to move the focus.  The routine will*/
  963. /*                    stop at the end of the button list without wrapping  */
  964. /*                    around.                                              */
  965. /*                    Returns TRUE if focus moved, or FALSE if it ran out  */
  966. /*                    of buttons before finding a non-grayed one.          */
  967. /***************************************************************************/
  968. BOOL FAR PASCAL toolbarMoveFocus(HWND hwnd, BOOL fBackward)
  969. {
  970.     int     iBtnPos, iButton, nOffset, nStopAt;
  971.     RECT    rc;
  972.     int iPrevPos = GETWHICH(hwnd);     /* Who used to have focus? */
  973.  
  974.     /* Fix illegal value.  It's OK to be one less or greater than range */
  975.     if (iPrevPos < -1 || iPrevPos > GETNUMBUTTONS(hwnd))
  976.         SETWHICH(hwnd, 0);    // good a default as any
  977.  
  978.     if (fBackward) {
  979.         nOffset = -1;
  980.         nStopAt = -1;
  981.     } else {
  982.         nOffset = 1;
  983.         nStopAt = GETNUMBUTTONS(hwnd);
  984.     }
  985.             
  986.     /* look for next button that isn't grayed    */
  987.     /* DON'T wrap around - future code will pass */
  988.     /* the focus to another window (???)         */
  989.     for (iBtnPos = GETWHICH(hwnd) + nOffset;
  990.             iBtnPos != nStopAt;
  991.             iBtnPos += nOffset) {
  992.         iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  993.         if (toolbarStateFromButton(hwnd, iButton) !=
  994.                     BTNST_GRAYED) {
  995.         SETWHICH(hwnd, iBtnPos);    // set focus
  996.  
  997.         /* Redraw both old and new focused button */
  998.         toolbarRectFromIndex(hwnd, iPrevPos, &rc);
  999.         InvalidateRect(hwnd, &rc, FALSE);
  1000.         toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1001.         InvalidateRect(hwnd, &rc, FALSE);
  1002.         break;
  1003.  
  1004.         }
  1005.     }
  1006.  
  1007.     if (GETWHICH(hwnd) != iPrevPos)
  1008.         return TRUE;
  1009.     else
  1010.         return FALSE;
  1011. }
  1012.  
  1013. /***************************************************************************/
  1014. /* toolbarSetFocus :  Set the focus in the toolbar to the specified button.*/
  1015. /*                    If it's gray, it'll set focus to next ungrayed btn.  */
  1016. /*                    Returns TRUE if focus set, or FALSE if the button    */
  1017. /*                    doesn't exist or if it and all buttons after it were */
  1018. /*                    grayed...       You can use TB_FIRST or TB_LAST in   */
  1019. /*                    place of a button ID.  This uses the first or last   */
  1020. /*                    un-grayed button.                                    */
  1021. /***************************************************************************/
  1022. BOOL FAR PASCAL toolbarSetFocus(HWND hwnd, int iButton)
  1023. {
  1024.     int iBtnPos;
  1025.     RECT rc;
  1026.  
  1027.     /* Don't move focus while a button is down */
  1028.     if (GetCapture() != hwnd && !GETKEYPRESSED(hwnd)) {
  1029.  
  1030.     /* redraw button with focus in case focus moves */
  1031.     toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1032.     InvalidateRect(hwnd, &rc, FALSE);
  1033.  
  1034.     if (iButton == TB_FIRST) {
  1035.         SETWHICH(hwnd, -1); // move forward to 1st button
  1036.         return toolbarMoveFocus(hwnd, FALSE);
  1037.     } else if (iButton == TB_LAST) {
  1038.         SETWHICH(hwnd, GETNUMBUTTONS(hwnd));
  1039.         return toolbarMoveFocus(hwnd, TRUE);
  1040.     } else {
  1041.         iBtnPos = toolbarIndexFromButton(hwnd, iButton);
  1042.         if (iBtnPos != -1) {
  1043.         SETWHICH(hwnd, --iBtnPos);
  1044.         return toolbarMoveFocus(hwnd, FALSE);
  1045.         } else
  1046.         return FALSE;
  1047.     }
  1048.     return TRUE;
  1049.  
  1050.     } else
  1051.     return FALSE;
  1052. }
  1053.  
  1054. //
  1055. //  LoadUIBitmap() - load a bitmap resource
  1056. //
  1057. //      load a bitmap resource from a resource file, converting all
  1058. //      the standard UI colors to the current user specifed ones.
  1059. //
  1060. //      this code is designed to load bitmaps used in "gray ui" or
  1061. //      "toolbar" code.
  1062. //
  1063. //      the bitmap must be a 4bpp windows 3.0 DIB, with the standard
  1064. //      VGA 16 colors.
  1065. //
  1066. //      the bitmap must be authored with the following colors
  1067. //
  1068. //          Button Text        Black        (index 0)
  1069. //          Button Face        lt gray      (index 7)
  1070. //          Button Shadow      gray         (index 8)
  1071. //          Button Highlight   white        (index 15)
  1072. //          Window Color       yellow       (index 11)
  1073. //          Window Frame       green        (index 10)
  1074. //
  1075. //      Example:
  1076. //
  1077. //          hbm = LoadUIBitmap(hInstance, "TestBmp",
  1078. //              GetSysColor(COLOR_BTNTEXT),
  1079. //              GetSysColor(COLOR_BTNFACE),
  1080. //              GetSysColor(COLOR_BTNSHADOW),
  1081. //              GetSysColor(COLOR_BTNHIGHLIGHT),
  1082. //              GetSysColor(COLOR_WINDOW),
  1083. //              GetSysColor(COLOR_WINDOWFRAME));
  1084. //
  1085. //      Author:     JimBov, ToddLa
  1086. //
  1087. //
  1088.  
  1089. HBITMAP FAR PASCAL  LoadUIBitmap(
  1090.     HANDLE      hInstance,          // EXE file to load resource from
  1091.     LPCSTR      szName,             // name of bitmap resource
  1092.     COLORREF    rgbText,            // color to use for "Button Text"
  1093.     COLORREF    rgbFace,            // color to use for "Button Face"
  1094.     COLORREF    rgbShadow,          // color to use for "Button Shadow"
  1095.     COLORREF    rgbHighlight,       // color to use for "Button Hilight"
  1096.     COLORREF    rgbWindow,          // color to use for "Window Color"
  1097.     COLORREF    rgbFrame)           // color to use for "Window Frame"
  1098. {
  1099.     LPBYTE              lpb;
  1100.     HBITMAP             hbm;
  1101.     LPBITMAPINFOHEADER  lpbi;
  1102.     HANDLE              h;
  1103.     HDC                 hdc;
  1104.     LPDWORD             lprgb;
  1105.     int isize;
  1106.     HANDLE hmem;
  1107.     LPBYTE lpCopy;
  1108.  
  1109.     // convert a RGB into a RGBQ
  1110.     #define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw))
  1111.  
  1112.     h = LoadResource (hInstance,FindResource(hInstance, szName, RT_BITMAP));
  1113.  
  1114.     lpbi = (LPBITMAPINFOHEADER)LockResource(h);
  1115.  
  1116.     if (!lpbi)
  1117.         return(NULL);
  1118.  
  1119.     if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
  1120.         return NULL;
  1121.  
  1122.     if (lpbi->biBitCount != 4)
  1123.         return NULL;
  1124.  
  1125.     /*
  1126.      * copy the resource since they are now loaded read-only
  1127.      */
  1128. #ifdef _WIN32
  1129.     isize = lpbi->biSize + lpbi->biSizeImage +
  1130.             ((int)lpbi->biClrUsed ?
  1131.                     (int)lpbi->biClrUsed :
  1132.                     (1 << (int)lpbi->biBitCount))
  1133.             * sizeof(RGBQUAD);
  1134.     hmem = GlobalAlloc(GHND, isize);
  1135.     lpCopy = GlobalLock(hmem);
  1136.     if ((hmem == NULL) || (lpCopy == NULL)) {
  1137.         UnlockResource(h);
  1138.         FreeResource(h);
  1139.         return(NULL);
  1140.     }
  1141.  
  1142.  
  1143.     CopyMemory(lpCopy, lpbi, isize);
  1144.     UnlockResource(h);
  1145.     FreeResource(h);
  1146.  
  1147.     lpbi = (LPBITMAPINFOHEADER)lpCopy;
  1148. #endif
  1149.  
  1150.     /* Calcluate the pointer to the Bits information */
  1151.     /* First skip over the header structure */
  1152.  
  1153.     lprgb = (LPDWORD)((LPBYTE)(lpbi) + lpbi->biSize);
  1154.  
  1155.     /* Skip the color table entries, if any */
  1156.     lpb = (LPBYTE)lprgb + ((int)lpbi->biClrUsed ? (int)lpbi->biClrUsed :
  1157.         (1 << (int)lpbi->biBitCount)) * sizeof(RGBQUAD);
  1158.  
  1159.     lprgb[0]  = RGBQ(rgbText);          // Black
  1160.     lprgb[7]  = RGBQ(rgbFace);          // lt gray
  1161.     lprgb[8]  = RGBQ(rgbShadow);        // gray
  1162.     lprgb[15] = RGBQ(rgbHighlight);     // white
  1163.     lprgb[11] = RGBQ(rgbWindow);        // yellow
  1164.     lprgb[10] = RGBQ(rgbFrame);         // green
  1165.  
  1166.     hdc = GetDC(NULL);
  1167.  
  1168.     hbm = CreateDIBitmap (hdc, lpbi, CBM_INIT, (LPVOID)lpb,
  1169.         (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  1170.  
  1171.     ReleaseDC(NULL, hdc);
  1172.     UnlockResource(h);
  1173.     FreeResource(h);
  1174.  
  1175.     return(hbm);
  1176. }
  1177.  
  1178. /****************************************************************************
  1179.     toolbarWndProc()
  1180.  
  1181.     Window proc for toolbar.
  1182.  
  1183.     Arguments:
  1184.         Standard window proc
  1185. ****************************************************************************/
  1186.  
  1187. LONG FAR PASCAL toolbarWndProc(HWND hwnd, unsigned message,
  1188.                         UINT wParam, LONG lParam)
  1189. {
  1190.     PAINTSTRUCT    ps;
  1191.     POINT        pt;
  1192.     RECT        rc;
  1193.     int            iBtnPos, iButton, ibmp;
  1194.     HANDLE        lpaButtons, hbm, hInst;
  1195.  
  1196.     switch (message) {
  1197.  
  1198.         case WM_CREATE:            // do all initialization
  1199.         
  1200.         /* What do these do? */
  1201.         SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  1202.                         SWP_NOZORDER | SWP_NOSIZE |
  1203.                     SWP_NOMOVE | SWP_NOACTIVATE);
  1204.         SetWindowLong(hwnd,GWL_STYLE,lpCreate->style & 0xFFFF00FF);
  1205.         
  1206.         /* Alloc some space for the array of buttons on this bar */
  1207.         lpaButtons = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  1208.                     TOOLGROW * sizeof(TOOLBUTTON));
  1209.  
  1210.         SETARRAYBUTT(hwnd, lpaButtons);    // list of buttons on toolbar
  1211.         SETNUMBUTTONS(hwnd, 0);        // # buttons in toolbar
  1212.         SETPRESSED(hwnd, FALSE);    // mouse button being pressed?
  1213.         SETKEYPRESSED(hwnd, FALSE);    // is a key being pressed?
  1214.         SETWHICH(hwnd, -1);        // which button has the focus?
  1215.         SETSHIFTED(hwnd, FALSE);    // shift-click or right-click?
  1216.  
  1217.         /* This wParam will be sent to the parent window to indentify */
  1218.         /* that the toolbar sent the WM_COMMAND msg.  The hwnd of the */
  1219.         /* toolbar that sent the msg will be in the lParam.          */
  1220. #ifdef _WIN32
  1221.         SetWindowLong(hwnd, GWL_ID, IDC_TOOLBAR);
  1222. #else
  1223.         SetWindowWord(hwnd, GWW_ID, (WORD)IDC_TOOLBAR);
  1224. #endif
  1225.  
  1226.         /* later on, someone will set the bmp handle of the buttons */
  1227.         SETBMPHANDLE(hwnd, NULL);
  1228.  
  1229.         break;
  1230.  
  1231.         case WM_LBUTTONDOWN:    // button goes down on a toolbar button
  1232.         case WM_RBUTTONDOWN:
  1233.         case WM_LBUTTONDBLCLK:
  1234.         case WM_RBUTTONDBLCLK:
  1235.  
  1236.         /* If we don't give ourself focus, we'll never get KEYDOWN */
  1237.         /* or KEYUP messages.                       */
  1238.         /* Get the focus only if we're a TABSTOP and the app wants */
  1239.         /* us to take focus.                       */
  1240.         if ( (GetWindowLong(hwnd, GWL_STYLE) & WS_TABSTOP)
  1241.                         && GetFocus() != hwnd)
  1242.             SetFocus(hwnd);
  1243.  
  1244.         /* ignore messages if window is disabled */
  1245.         if (!IsWindowEnabled(hwnd))
  1246.             return 0L;
  1247.  
  1248.         /* ignore multiple down messages (we set Capture here) */
  1249.         /* also ignore if a key is down                        */
  1250.         if (GetCapture() == hwnd || GETPRESSED(hwnd))
  1251.             return 0L;
  1252.         
  1253.         /* Where did the mouse go down? */
  1254.                 pt.x = (short)LOWORD(lParam);
  1255.                 pt.y = (short)HIWORD(lParam);
  1256.  
  1257.         /* which button was pressed? */
  1258.         iBtnPos = toolbarIndexFromPoint(hwnd, pt);
  1259.  
  1260.         /* If it was a valid button... */
  1261.         if (iBtnPos >= 0) {
  1262.             int        iOldPos;
  1263.             int        iState, iType, iButton;
  1264.  
  1265.             /* Everything you wanted to know about this button */
  1266.             iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1267.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1268.             iState = toolbarFullStateFromButton(hwnd, iButton);
  1269.  
  1270.             /* ignore downs on a grayed button, unless it's a    */
  1271.             /* custom button, then tell them anyway        */
  1272.             if (iType != BTNTYPE_CUSTOM && iState == BTNST_GRAYED)
  1273.             return 0;
  1274.  
  1275.             /* We better get all mouse messages from now on */
  1276.             SetCapture(hwnd);
  1277.  
  1278.             /* Shift key or right button indicates a SHIFT down */
  1279.             SETSHIFTED(hwnd, (message == WM_RBUTTONDOWN) ||
  1280.                             (wParam & MK_SHIFT));
  1281.  
  1282.             /* Yes, we've pressed the button down */
  1283.             SETPRESSED(hwnd, TRUE);
  1284.  
  1285.             /* Remember who used to have the focus, and we get it now */
  1286.             iOldPos = GETWHICH(hwnd);
  1287.             SETWHICH(hwnd, iBtnPos);
  1288.  
  1289.             /* For a push button, send it down */
  1290.             if (iType == BTNTYPE_PUSH)
  1291.             toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1292.  
  1293.             /* for a checkbox or radio button (of any group),       */
  1294.             /* remember what state it was in, and send it FULL down */
  1295.             /* (with focus).                        */
  1296.             if (iType == BTNTYPE_CHECKBOX || iType >= BTNTYPE_RADIO) {
  1297.             toolbarModifyPrevState(hwnd, iButton, iState);
  1298.             toolbarModifyState(hwnd,iButton,BTNST_FULLDOWN);
  1299.             }
  1300.  
  1301.             toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEDOWN);
  1302.  
  1303.             /* Set Double click flag appropriately */
  1304.             if (message == WM_LBUTTONDBLCLK ||
  1305.                         message == WM_RBUTTONDBLCLK)
  1306.             NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0)
  1307.                          + BTN_DBLCLICK + iButton);
  1308.             else
  1309.             NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0)
  1310.                          + iButton);
  1311.  
  1312.             /* Invalidate the Rect of the button being pressed */
  1313.             toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1314.             InvalidateRect(hwnd, &rc, FALSE);
  1315.  
  1316.             /* Invalidate the Rect of the button losing focus */
  1317.             toolbarRectFromIndex(hwnd, iOldPos, &rc);
  1318.             InvalidateRect(hwnd, &rc, FALSE);
  1319.  
  1320.             /* Force re-paint now */
  1321.             UpdateWindow(hwnd);
  1322.  
  1323.             /* Set a timer for repeated mouse downs */
  1324.             SetTimer(hwnd, TIMER_BUTTONREPEAT,
  1325.                  MSEC_BUTTONREPEAT, NULL);
  1326.         }
  1327.         
  1328.         return 0L;
  1329.  
  1330.         case WM_MOUSEMOVE:
  1331.  
  1332. #if 0
  1333.         /* This should be impossible - it means that the system lost */
  1334.         /* a mouse up (maybe codeview is up?) We need to force a     */
  1335.         /* mouse up at this point.                     */
  1336.         if (GetCapture() == hwnd &&
  1337.             (wParam & (MK_LBUTTON | MK_RBUTTON) == 0))
  1338.             SendMessage(hwnd, WM_LBUTTONUP, 0, lParam);
  1339. #endif
  1340.  
  1341.         /* Mouse moving while pressing a button?  If not, ignore. */
  1342.         if (GetCapture() == hwnd) {
  1343.             int        iPrevState, iState, iButton, iType;
  1344.             BOOL    fPressed;
  1345.         
  1346.             /* Which button is being pressed down? */
  1347.             iBtnPos = GETWHICH(hwnd);
  1348.  
  1349.             /* Where is mouse cursor now? */
  1350.                     pt.x = (short)LOWORD(lParam);
  1351.                     pt.y = (short)HIWORD(lParam);
  1352.  
  1353.             /* where is button being pressed? Are we still on */
  1354.             /* top of that button or have we moved?          */
  1355.             toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1356.             fPressed = PtInRect(&rc, pt);
  1357.  
  1358.             /* Let go if we move off of the button, but don't */
  1359.             /* act like it was pressed.                       */
  1360.             /* Also, push it back down if we move back on top */
  1361.             /* of it (while the mouse button is STILL down).  */
  1362.             if (fPressed != GETPRESSED(hwnd)) {
  1363.  
  1364.             /* update: is this button pressed anymore? */
  1365.             SETPRESSED(hwnd, fPressed);
  1366.  
  1367.             iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1368.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1369.             iState = toolbarFullStateFromButton(hwnd, iButton);
  1370.  
  1371.             /* The mouse moved back onto the button while */
  1372.             /* the mouse button was still pressed.          */
  1373.             if (fPressed) {
  1374.  
  1375.                 /* Push the push button back down again */
  1376.                  if (iType == BTNTYPE_PUSH)
  1377.                 toolbarModifyState(hwnd, iButton,
  1378.                             BTNST_DOWN);
  1379.  
  1380.                 /* Push the radio or checkbox button ALL the */
  1381.                 /* way down again.                 */
  1382.                 if (iType >= BTNTYPE_RADIO ||
  1383.                         iType == BTNTYPE_CHECKBOX)
  1384.                 toolbarModifyState(hwnd, iButton,
  1385.                             BTNST_FULLDOWN);
  1386.  
  1387.                 toolbarModifyActivity(hwnd, iButton,
  1388.                             BTNACT_MOUSEMOVEON);
  1389.                 NotifyParent(hwnd,
  1390.                     (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1391.                     iButton);
  1392.  
  1393.             /* We moved the mouse off of the toolbar button */
  1394.             /* while still holding the mouse button down.   */
  1395.             } else {
  1396.  
  1397.                 /* lift the push button up */
  1398.                  if (iType == BTNTYPE_PUSH)
  1399.                 toolbarModifyState(hwnd, iButton,
  1400.                             BTNST_UP);
  1401.  
  1402.                 /* Restore radio button or checkbox button to */
  1403.                 /* where it was before pressed          */
  1404.                 if (iType >= BTNTYPE_RADIO ||
  1405.                         iType == BTNTYPE_CHECKBOX) {
  1406.                 iPrevState = toolbarPrevStateFromButton(hwnd,
  1407.                             iButton);
  1408.                 toolbarModifyState(hwnd, iButton, iPrevState);
  1409.                 }
  1410.  
  1411.                 toolbarModifyActivity(hwnd, iButton,
  1412.                             BTNACT_MOUSEMOVEOFF);
  1413.                 NotifyParent(hwnd,
  1414.                     (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1415.                     toolbarButtonFromIndex(hwnd, iBtnPos));
  1416.             }
  1417.             }
  1418.         }
  1419.         return 0L;
  1420.  
  1421.         case WM_LBUTTONUP:    
  1422.         case WM_RBUTTONUP:
  1423.  
  1424.         /* If we don't have capture, we aren't expecting this. Ignore */
  1425.         if (GetCapture() == hwnd) {
  1426.             int        iPrevState, iState, iButton, iType;
  1427.         
  1428.             /* Who has the focus? */
  1429.             iBtnPos = GETWHICH(hwnd);
  1430.  
  1431.             /* Release the mouse */
  1432.             ReleaseCapture();
  1433.         
  1434.             /* No more repeats of the mouse button downs */
  1435.             KillTimer(hwnd, TIMER_BUTTONREPEAT);
  1436.         
  1437.             /* Everything you wanted to know about the button */
  1438.             toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1439.             iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1440.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1441.             iState = toolbarFullStateFromButton(hwnd, iButton);
  1442.  
  1443.             /* Don't do anything if we've moved off the button */
  1444.             if (GETPRESSED(hwnd)) {
  1445.  
  1446.             /* No longer down */
  1447.             SETPRESSED(hwnd, FALSE);
  1448.  
  1449.             /* Bring the push button up */
  1450.             if (iType == BTNTYPE_PUSH)
  1451.                 toolbarModifyState(hwnd, iButton, BTNST_UP);
  1452.  
  1453.             /* Bring the checkbox to the opposite state it was in */
  1454.             if (iType == BTNTYPE_CHECKBOX) {
  1455.                 iPrevState = toolbarPrevStateFromButton(hwnd,
  1456.                             iButton);
  1457.                 if (iPrevState == BTNST_DOWN)
  1458.                 toolbarModifyState(hwnd, iButton, BTNST_UP);
  1459.                 if (iPrevState == BTNST_UP)
  1460.                 toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1461.             }
  1462.  
  1463.             /* Force a radio button down, and bring all   */
  1464.             /* other radio buttons of this type up          */
  1465.             if (iType >= BTNTYPE_RADIO) {
  1466.                 toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1467.                 toolbarExclusiveRadio(hwnd, iType, iButton);
  1468.             }
  1469.  
  1470.             /* Notify the parent that the mouse button came up */
  1471.             /* on this button so the app can do something.     */
  1472.             /* Every button should notify the app, not just a  */
  1473.             /* custom button.                   */
  1474.             toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEUP);
  1475.             NotifyParent(hwnd,
  1476.                 (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton);
  1477.             }
  1478.         }
  1479.  
  1480.         return 0L;
  1481.  
  1482.         
  1483.     case WM_TIMER:
  1484.  
  1485.         /* If we have a tool button down, send a repeat message */
  1486.         if (GETPRESSED(hwnd)) {
  1487.             int        iButton, iType;
  1488.  
  1489.             iBtnPos = GETWHICH(hwnd);
  1490.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1491.             iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1492.  
  1493.             NotifyParent(hwnd, BTN_REPEAT +
  1494.                     (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1495.                     toolbarButtonFromIndex(hwnd, iBtnPos));
  1496.         }
  1497.         break;
  1498.         
  1499.  
  1500.         case WM_DESTROY:
  1501.         if (GETBMPHANDLE(hwnd))
  1502.             DeleteObject(GETBMPHANDLE(hwnd));
  1503.         SETBMPHANDLE(hwnd, NULL);
  1504.         if (GETARRAYBUTT(hwnd))
  1505.             GlobalFree(GETARRAYBUTT(hwnd));
  1506.         SETARRAYBUTT(hwnd, NULL);
  1507.         break;
  1508.  
  1509.         case WM_SETTEXT:
  1510.         break;
  1511.         
  1512. /* MANY, MANY cases deleted */
  1513.  
  1514.     case WM_SETFOCUS:        // focus comes to toolbar window
  1515.         {
  1516.         /* Remember who had the focus and give it back.  Of course, */
  1517.         /* if by some wierdness that button is now grayed, give it  */
  1518.         /* to the next person in line.                    */
  1519.         iBtnPos = GETWHICH(hwnd);
  1520.         if (iBtnPos < 0 || iBtnPos >= toolbarGetNumButtons(hwnd)) {
  1521.             iBtnPos = 0;
  1522.             SETWHICH(hwnd, 0);
  1523.         }
  1524.  
  1525.         do {
  1526.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1527.             if (toolbarFullStateFromButton(hwnd, iButton)
  1528.                             != BTNST_GRAYED)
  1529.             break;            // give it here
  1530.             iBtnPos++;
  1531.             if (iBtnPos >= toolbarGetNumButtons(hwnd))
  1532.             iBtnPos = 0;        // wrap around
  1533.             if (iBtnPos == GETWHICH(hwnd))
  1534.             return 0L;        // uh-oh! They're all gray!
  1535.         } while (iBtnPos != GETWHICH(hwnd));
  1536.             
  1537.         SETWHICH(hwnd, iBtnPos);    // give focus here
  1538.         
  1539.         /* And redraw! */
  1540.         toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1541.         InvalidateRect(hwnd, &rc, FALSE);
  1542.         UpdateWindow(hwnd);
  1543.         return 0;
  1544.         }
  1545.     
  1546.     case WM_KILLFOCUS:
  1547.  
  1548.         /* Send a KEYUP if one is pending */
  1549.         if (GETKEYPRESSED(hwnd))
  1550.             SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L);
  1551.  
  1552.         /* Redraw the focused button, because now that focus is gone */
  1553.         /* from our toolbar window, the focused button won't be      */
  1554.         /* focused anymore, although we remember which one it was.   */
  1555.         toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1556.         InvalidateRect(hwnd, &rc, FALSE);
  1557.         UpdateWindow(hwnd);
  1558.         return 0;
  1559.  
  1560.     case WM_SYSKEYDOWN:
  1561.         /* Send a KEYUP if one is pending */
  1562.         if (GETKEYPRESSED(hwnd))
  1563.             SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L);
  1564.         break;    // MUST LET DEFWNDPROC RUN!!! (to handle the key)
  1565.  
  1566.         case WM_GETDLGCODE:
  1567.         return DLGC_WANTARROWS | DLGC_WANTTAB;
  1568.  
  1569.     case WM_KEYDOWN:
  1570.  
  1571.         /* Window disabled or a key is already down */
  1572.         if (IsWindowEnabled(hwnd) && !GETPRESSED(hwnd)) {
  1573.  
  1574.             /* Tab forward to next button and move focus there */
  1575.             if (wParam == VK_TAB && GetKeyState(VK_SHIFT) >= 0 ) {
  1576.  
  1577.             /* Move Focus forward one.  If */
  1578.             /* we've tabbed off of the toolbar, it's time */
  1579.             /* to go on to the next control. We need to invldte */
  1580.             /* because we might be the only control and we need */
  1581.             /* to repaint to show the new button with highlight */
  1582.             /* after it wrapped around the end of the toolbar.  */
  1583.             if (!toolbarMoveFocus(hwnd, FALSE)) {
  1584.                 PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 0, 0L);
  1585.                 toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1586.                 InvalidateRect(hwnd, &rc, FALSE);
  1587.             }
  1588.  
  1589.             return 0L;
  1590.             }
  1591.             if (wParam == VK_TAB && GetKeyState(VK_SHIFT) < 0 ) {
  1592.  
  1593.             /* Move focus backward one.  If */
  1594.             /* We've tabbed off of the toolbar, it's time    */
  1595.             /* to go on to the next control. We need to invldte */
  1596.             /* because we might be the only control and we need */
  1597.             /* to repaint to show the new button with highlight */
  1598.             /* after it wrapped around the end of the toolbar.  */
  1599.             if (!toolbarMoveFocus(hwnd, TRUE)) {
  1600.                 PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 1, 0L);
  1601.                 toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1602.                 InvalidateRect(hwnd, &rc, FALSE);
  1603.             }
  1604.  
  1605.             return 0L;
  1606.             }
  1607.             if ((wParam == VK_SPACE) && (GetCapture() != hwnd)) {
  1608.  
  1609.             int    iButton, iType, iState;
  1610.  
  1611.             /* Same as mouse button down -- Press the button! */
  1612.             iBtnPos = GETWHICH(hwnd);
  1613.             iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1614.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1615.             iState = toolbarFullStateFromButton(hwnd, iButton);
  1616.  
  1617.             /* ignore multiple key downs */
  1618.             if (!GETKEYPRESSED(hwnd)) {
  1619.  
  1620.                 SETKEYPRESSED(hwnd, TRUE);    // a key is pressed
  1621.  
  1622.                 SETSHIFTED(hwnd, FALSE);    // NEVER shifted
  1623.                 SETPRESSED(hwnd, TRUE);    // a button is pressed
  1624.  
  1625.                 /* Push button goes down - with focus */
  1626.                 if (iType == BTNTYPE_PUSH)
  1627.                 toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1628.  
  1629.                 /* Radio or checkbox button goes full down */
  1630.                 /* with focus - and remember previous state*/
  1631.                 if (iType >= BTNTYPE_RADIO ||
  1632.                         iType == BTNTYPE_CHECKBOX) {
  1633.                 toolbarModifyPrevState(hwnd, iButton, iState);
  1634.                 toolbarModifyState(hwnd, iButton,
  1635.                             BTNST_FULLDOWN);
  1636.                 }
  1637.  
  1638.                 toolbarModifyActivity(hwnd, iButton,
  1639.                                 BTNACT_KEYDOWN);
  1640.                 NotifyParent(hwnd, (GETSHIFTED(hwnd)
  1641.                         ? BTN_SHIFT : 0) + iButton);
  1642.  
  1643.                 return 0L;
  1644.             }
  1645.         
  1646.             /* If this is another KEYDOWN msg, it's a REPEAT */
  1647.             /* Notify parent.                                */
  1648.             NotifyParent(hwnd, BTN_REPEAT +
  1649.                     (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1650.                     toolbarButtonFromIndex(hwnd,
  1651.                             GETWHICH(hwnd)));
  1652.             }
  1653.         }
  1654.         break;
  1655.     
  1656.     case WM_KEYUP:
  1657.  
  1658.         /* A button was pressed and should come up now */
  1659.         if ((wParam == VK_SPACE) && (GETKEYPRESSED(hwnd))) {
  1660.             int        iButton, iState, iType, iPrevState;
  1661.  
  1662.             iBtnPos = GETWHICH(hwnd);        // which button?
  1663.             SETKEYPRESSED(hwnd, FALSE);        // let go
  1664.             SETPRESSED(hwnd, FALSE);
  1665.  
  1666.             /* Everything about this button */
  1667.             toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1668.             iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1669.             iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1670.             iState = toolbarFullStateFromButton(hwnd, iButton);
  1671.  
  1672.             /* Bring a push button up */
  1673.             if (iType == BTNTYPE_PUSH)
  1674.             toolbarModifyState(hwnd, iButton, BTNST_UP);
  1675.  
  1676.             /* Bring a checkbox to the opposite state it was in */
  1677.             if (iType == BTNTYPE_CHECKBOX) {
  1678.             iPrevState = toolbarPrevStateFromButton(hwnd, iButton);
  1679.             if (iPrevState == BTNST_DOWN)
  1680.                 toolbarModifyState(hwnd, iButton, BTNST_UP);
  1681.             if (iPrevState == BTNST_UP)
  1682.                 toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1683.             }
  1684.  
  1685.             /* Bring a radio button down, and bring all others in */
  1686.             /* its group up.                      */
  1687.             if (iType >= BTNTYPE_RADIO) {
  1688.             toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1689.             toolbarExclusiveRadio(hwnd, iType, iButton);
  1690.             }
  1691.  
  1692.             toolbarModifyActivity(hwnd, iButton, BTNACT_KEYUP);
  1693.             NotifyParent(hwnd, toolbarButtonFromIndex(hwnd,
  1694.                     (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1695.                     GETWHICH(hwnd)));
  1696.         }
  1697.         break;
  1698.     
  1699.     case WM_SYSCOLORCHANGE:
  1700.         /* load the bitmap of what all the buttons look like */
  1701.         /* and change the colours to the system colours.     */
  1702.         hInst = GETHINST(hwnd);
  1703.         ibmp = GETBMPINT(hwnd);
  1704.         hbm = GETBMPHANDLE(hwnd);
  1705.         if (hbm)
  1706.             DeleteObject(hbm);
  1707.         hbm = LoadUIBitmap(hInst, MAKEINTRESOURCE(ibmp),
  1708.             GetSysColor(COLOR_BTNTEXT),
  1709.             GetSysColor(COLOR_BTNFACE),
  1710.             GetSysColor(COLOR_BTNSHADOW),
  1711.             GetSysColor(COLOR_BTNHIGHLIGHT),
  1712.             GetSysColor(COLOR_BTNFACE),
  1713.             GetSysColor(COLOR_WINDOWFRAME));
  1714.         SETBMPHANDLE(hwnd, hbm);
  1715. #ifdef _WIN32
  1716.         return (long) hbm;
  1717. #else
  1718.         return MAKELONG(hbm, 0);
  1719. #endif
  1720.  
  1721.         case WM_ERASEBKGND:
  1722.         break;
  1723.  
  1724.  
  1725.         case WM_PAINT:
  1726.  
  1727.         /* Call our paint code */
  1728.         BeginPaint(hwnd, &ps);
  1729.         toolbarPaintControl(hwnd, ps.hdc);
  1730.         EndPaint(hwnd, &ps);
  1731.  
  1732.         return 0L;
  1733.     }
  1734.  
  1735.     return DefWindowProc(hwnd, message, wParam, lParam);
  1736.  
  1737. }
  1738.