TOOLBAR.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:55k
源码类别:

Windows编程

开发平台:

Visual C++

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