Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1737 lines
54 KiB

4 years ago
  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 - 1995 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. /* Get the array of buttons */
  447. h = GETARRAYBUTT(hwnd);
  448. if (!h)
  449. return FALSE;
  450. lpButton = (TOOLBUTTON far *)GlobalLock(h);
  451. /* look for what we need */
  452. for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  453. if (lpButton->iButton == iButton) {
  454. *lptb = *lpButton;
  455. fFound = TRUE;
  456. break;
  457. }
  458. GlobalUnlock(h);
  459. return fFound;
  460. }
  461. /***************************************************************************/
  462. /* toolbarRemoveTool: Remove this button ID from our array of buttons on */
  463. /* the toolbar. (only 1 of each button ID allowed). */
  464. /* Return FALSE for an error. */
  465. /***************************************************************************/
  466. BOOL FAR PASCAL toolbarRemoveTool(HWND hwnd, int iButton)
  467. {
  468. HANDLE h;
  469. TOOLBUTTON far *lpaButtons;
  470. int cButtons, i, j;
  471. BOOL fFound = FALSE;
  472. /* Get the array of buttons */
  473. h = GETARRAYBUTT(hwnd);
  474. if (!h)
  475. return FALSE;
  476. /* How many buttons are on there now? */
  477. cButtons = GETNUMBUTTONS(hwnd);
  478. lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  479. /* Find a match, remove it, and close the array around it. */
  480. for (i = 0; i < cButtons; i++)
  481. if (lpaButtons[i].iButton == iButton) {
  482. fFound = TRUE;
  483. // redraw now
  484. InvalidateRect(hwnd, &(lpaButtons[i].rc), FALSE);
  485. if (i != cButtons - 1) // Last button? Don't bother!
  486. for (j = i; j < cButtons; j++)
  487. lpaButtons[j] = lpaButtons[j + 1];
  488. break;
  489. }
  490. GlobalUnlock(h);
  491. /* Didn't find it! */
  492. if (!fFound)
  493. return FALSE;
  494. /* One less button */
  495. cButtons--;
  496. /* Every once in a while, re-alloc a smaller array chunk to */
  497. /* save memory. */
  498. if ( ((cButtons & (TOOLGROW - 1)) == 0) && (cButtons > 0) ) {
  499. /* Re-alloc it smaller */
  500. h = GlobalReAlloc(h,
  501. GlobalSize(h) - TOOLGROW * sizeof(TOOLBUTTON),
  502. GMEM_MOVEABLE | GMEM_SHARE);
  503. if (!h)
  504. return FALSE;
  505. }
  506. SETNUMBUTTONS(hwnd, cButtons); // new count
  507. SETARRAYBUTT(hwnd, h); // re-alloc could have changed it
  508. return TRUE;
  509. }
  510. /***************************************************************************/
  511. /* toolbarModifyString: Given a button ID on the toolbar, change it's */
  512. /* string resource associated with it. */
  513. /* returns FALSE for an error or if no such button */
  514. /***************************************************************************/
  515. BOOL FAR PASCAL toolbarModifyString(HWND hwnd, int iButton, int iString)
  516. {
  517. HANDLE h;
  518. TOOLBUTTON far *lpButton;
  519. int cButtons, i;
  520. BOOL fFound = FALSE;
  521. /* Get the array of buttons */
  522. h = GETARRAYBUTT(hwnd);
  523. if (!h)
  524. return FALSE;
  525. /* How many buttons? */
  526. cButtons = GETNUMBUTTONS(hwnd);
  527. lpButton = (TOOLBUTTON far *)GlobalLock(h);
  528. /* Find that button, and change it's state */
  529. for (i = 0; i < cButtons; i++, lpButton++)
  530. if (lpButton->iButton == iButton) {
  531. lpButton->iString = iString;
  532. fFound = TRUE; // redraw now
  533. break;
  534. }
  535. GlobalUnlock(h);
  536. return fFound;
  537. }
  538. /***************************************************************************/
  539. /* toolbarModifyState: Given a button ID on the toolbar, change it's */
  540. /* state. */
  541. /* returns FALSE for an error or if no such button */
  542. /***************************************************************************/
  543. BOOL FAR PASCAL toolbarModifyState(HWND hwnd, int iButton, int iState)
  544. {
  545. HANDLE h;
  546. TOOLBUTTON far *lpButton;
  547. int cButtons, i;
  548. BOOL fFound = FALSE;
  549. /* Get the array of buttons */
  550. h = GETARRAYBUTT(hwnd);
  551. if (!h)
  552. return FALSE;
  553. /* How many buttons? */
  554. cButtons = GETNUMBUTTONS(hwnd);
  555. lpButton = (TOOLBUTTON far *)GlobalLock(h);
  556. /* Find that button, and change it's state */
  557. for (i = 0; i < cButtons; i++, lpButton++)
  558. if (lpButton->iButton == iButton) {
  559. if (lpButton->iState != iState) {
  560. lpButton->iState = iState;
  561. InvalidateRect(hwnd, &(lpButton->rc), FALSE);
  562. }
  563. fFound = TRUE; // redraw now
  564. /* if we're pushing a radio button down, bring */
  565. /* all others in its group up */
  566. if (lpButton->iType >= BTNTYPE_RADIO &&
  567. iState == BTNST_DOWN)
  568. toolbarExclusiveRadio(hwnd, lpButton->iType,
  569. iButton);
  570. break;
  571. }
  572. GlobalUnlock(h);
  573. return fFound;
  574. }
  575. /***************************************************************************/
  576. /* toolbarModifyPrevState: Given a button on the toolbar, change it's prev-*/
  577. /* ious state. Used for non-PUSH buttons to remember */
  578. /* what state a button was in before pressed all the */
  579. /* way down, so that when you let go, you know what */
  580. /* state to set it to (the opposite of what it was). */
  581. /* returns FALSE for an error (no button array) */
  582. /***************************************************************************/
  583. BOOL FAR PASCAL toolbarModifyPrevState(HWND hwnd, int iButton, int iPrevState)
  584. {
  585. HANDLE h;
  586. TOOLBUTTON far *lpButton;
  587. int cButtons, i;
  588. /* Get button array */
  589. h = GETARRAYBUTT(hwnd);
  590. if (!h)
  591. return FALSE;
  592. /* How many buttons? */
  593. cButtons = GETNUMBUTTONS(hwnd);
  594. lpButton = (TOOLBUTTON far *)GlobalLock(h);
  595. /* Find the button, change the state */
  596. for (i = 0; i < cButtons; i++, lpButton++)
  597. if (lpButton->iButton == iButton) {
  598. lpButton->iPrevState = iPrevState;
  599. break;
  600. }
  601. GlobalUnlock(h);
  602. return TRUE;
  603. }
  604. /***************************************************************************/
  605. /* toolbarModifyActivity: Given a button ID on the toolbar, change it's */
  606. /* activity. This tells the app what just happened */
  607. /* to the button (ie. KEYUP, MOUSEDBLCLK, etc.) */
  608. /* returns FALSE for an error or if no such button */
  609. /***************************************************************************/
  610. BOOL FAR PASCAL toolbarModifyActivity(HWND hwnd, int iButton, int iActivity)
  611. {
  612. HANDLE h;
  613. TOOLBUTTON far *lpButton;
  614. int cButtons, i;
  615. /* Get the button array */
  616. h = GETARRAYBUTT(hwnd);
  617. if (!h)
  618. return FALSE;
  619. /* How many buttons */
  620. cButtons = GETNUMBUTTONS(hwnd);
  621. lpButton = (TOOLBUTTON far *)GlobalLock(h);
  622. /* loop through and change the right one */
  623. for (i = 0; i < cButtons; i++, lpButton++)
  624. if (lpButton->iButton == iButton) {
  625. lpButton->iActivity = iActivity;
  626. break;
  627. }
  628. GlobalUnlock(h);
  629. return TRUE;
  630. }
  631. /***************************************************************************/
  632. /* toolbarFixFocus: SETWHICH() has been called to tell us which button */
  633. /* has the focus, but the states of all the buttons are */
  634. /* not updated (ie. take focus away from the old button) */
  635. /* This routine is called from the Paint routine to fix */
  636. /* the states of all the buttons before drawing them. */
  637. /* Returns FALSE for an error. */
  638. /***************************************************************************/
  639. BOOL FAR PASCAL toolbarFixFocus(HWND hwnd)
  640. {
  641. int iFocus;
  642. HANDLE h;
  643. TOOLBUTTON far *lpaButtons;
  644. /* Get the array of buttons */
  645. h = GETARRAYBUTT(hwnd);
  646. if (!h)
  647. return FALSE;
  648. lpaButtons = (TOOLBUTTON far *)GlobalLock(h);
  649. /* if focus is on an illegal button, default to the first one */
  650. iFocus = GETWHICH(hwnd);
  651. if (iFocus < 0 || iFocus >= GETNUMBUTTONS(hwnd))
  652. SETWHICH(hwnd, 0);
  653. /* First of all, make sure that the focus in not on a grayed button. */
  654. /* if so, we advance focus. If it runs out of buttons without */
  655. /* finding a non-gray one, we start back at the beginning and start */
  656. /* looking for a non-gray one from there. If every button is grayed,*/
  657. /* we leave no focus anywhere. */
  658. if (lpaButtons[GETWHICH(hwnd)].iState == BTNST_GRAYED) {
  659. if (!toolbarMoveFocus(hwnd, FALSE)) {
  660. SETWHICH(hwnd, -1);
  661. toolbarMoveFocus(hwnd, FALSE);
  662. }
  663. }
  664. GlobalUnlock(h);
  665. return TRUE;
  666. }
  667. /***************************************************************************/
  668. /* toolbarExclusiveRadio: For radio buttons, we need to pop all others */
  669. /* in the group up when one goes down. Pass the */
  670. /* button that is going down, and its group, and */
  671. /* this routine will pop all others up. */
  672. /* Returns FALSE for an error. */
  673. /***************************************************************************/
  674. BOOL FAR PASCAL toolbarExclusiveRadio(HWND hwnd, int iType, int iButton)
  675. {
  676. int i;
  677. HANDLE h;
  678. TOOLBUTTON far *lpButton;
  679. /* Get the array of buttons */
  680. h = GETARRAYBUTT(hwnd);
  681. if (!h)
  682. return FALSE;
  683. lpButton = (TOOLBUTTON far *)GlobalLock(h);
  684. /* all buttons with this type that aren't this button come up */
  685. /* if they are not grayed */
  686. for(i = 0; i < GETNUMBUTTONS(hwnd); i++, lpButton++)
  687. if (lpButton->iType == iType)
  688. if (lpButton->iButton != iButton &&
  689. lpButton->iState != BTNST_GRAYED) {
  690. toolbarModifyState(hwnd, lpButton->iButton, BTNST_UP);
  691. }
  692. GlobalUnlock(h);
  693. return TRUE;
  694. }
  695. /* NotifyParent() of activity to a button */
  696. static void NEAR PASCAL NotifyParent(HWND hwnd, int iButton)
  697. {
  698. #ifdef _WIN32
  699. PostMessage(
  700. GetParent(hwnd),
  701. WM_COMMAND,
  702. GET_WM_COMMAND_MPS(GetWindowLong(hwnd, GWL_ID), hwnd, iButton));
  703. #else
  704. PostMessage(GetParent(hwnd),WM_COMMAND,
  705. GetWindowWord(hwnd,GWW_ID),MAKELONG(hwnd,iButton));
  706. #endif
  707. }
  708. /***************************************************************************/
  709. /* toolbarPaintControl: Handles paint messages by blitting each bitmap */
  710. /* that is on the toolbar to its rect. */
  711. /* First, it fixes the states of the buttons to give */
  712. /* the focus to the proper button. */
  713. /* Returns FALSE for an error. */
  714. /***************************************************************************/
  715. static BOOL NEAR PASCAL toolbarPaintControl(HWND hwnd, HDC hdc)
  716. {
  717. int iBtnPos; /* 0 to toolbarGetNumButtons inclusive */
  718. int iButton; /* 0 to NUMBUTTONS-1 inclusive */
  719. int iState; /* 0 to NUMSTATES-1 inclusive */
  720. HDC hdcBtn; /* DC onto button bitmap */
  721. RECT rcDest;
  722. POINT pt;
  723. long l;
  724. HANDLE hbm;
  725. /* Make a source HDC for the button pictures, and select the button */
  726. /* bitmap into it. */
  727. hdcBtn = CreateCompatibleDC(hdc);
  728. if (!hdcBtn)
  729. return FALSE;
  730. hbm = GETBMPHANDLE(hwnd);
  731. if (hbm) {
  732. if (!SelectObject(hdcBtn, GETBMPHANDLE(hwnd))) {
  733. DeleteDC(hdcBtn);
  734. return FALSE;
  735. }
  736. }
  737. toolbarFixFocus(hwnd); // set the focus field correctly
  738. /* Go through all buttons on the toolbar */
  739. for (iBtnPos = 0; iBtnPos < toolbarGetNumButtons(hwnd); iBtnPos++) {
  740. iButton = toolbarButtonFromIndex(hwnd, iBtnPos); // button
  741. iState = toolbarFullStateFromButton(hwnd, iButton); // state
  742. toolbarRectFromIndex(hwnd, iBtnPos, &rcDest); // Dest Rect
  743. /* If we have the focus, we should draw it that way */
  744. if (GetFocus() == hwnd && GETWHICH(hwnd) == iBtnPos
  745. && iState == BTNST_UP)
  746. iState = BTNST_FOCUSUP;
  747. if (GetFocus() == hwnd && GETWHICH(hwnd) == iBtnPos
  748. && iState == BTNST_DOWN)
  749. iState = BTNST_FOCUSDOWN;
  750. /* If we don't have the focus, we should take it away */
  751. if ((GetFocus() != hwnd || GETWHICH(hwnd) != iBtnPos)
  752. && iState == BTNST_FOCUSUP)
  753. iState = BTNST_UP;
  754. if ((GetFocus() != hwnd || GETWHICH(hwnd) == iBtnPos)
  755. && iState == BTNST_FOCUSDOWN)
  756. iState = BTNST_DOWN;
  757. /* The size of each button */
  758. l = GETBUTTONSIZE(hwnd);
  759. pt.x = HIWORD(l);
  760. pt.y = LOWORD(l);
  761. /* Blit from the button picture to the toolbar window */
  762. BitBlt(hdc, rcDest.left, rcDest.top,
  763. rcDest.right - rcDest.left, rcDest.bottom - rcDest.top,
  764. hdcBtn, pt.x * iButton, pt.y * iState,
  765. SRCCOPY);
  766. }
  767. DeleteDC(hdcBtn);
  768. return TRUE;
  769. }
  770. /***************************************************************************/
  771. /* toolbarMoveFocus: Move Focus forward or backward one button. You give */
  772. /* it the direction to move the focus. The routine will*/
  773. /* stop at the end of the button list without wrapping */
  774. /* around. */
  775. /* Returns TRUE if focus moved, or FALSE if it ran out */
  776. /* of buttons before finding a non-grayed one. */
  777. /***************************************************************************/
  778. BOOL FAR PASCAL toolbarMoveFocus(HWND hwnd, BOOL fBackward)
  779. {
  780. int iBtnPos, iButton, nOffset, nStopAt;
  781. RECT rc;
  782. int iPrevPos = GETWHICH(hwnd); /* Who used to have focus? */
  783. /* Fix illegal value. It's OK to be one less or greater than range */
  784. if (iPrevPos < -1 || iPrevPos > GETNUMBUTTONS(hwnd))
  785. SETWHICH(hwnd, 0); // good a default as any
  786. if (fBackward) {
  787. nOffset = -1;
  788. nStopAt = -1;
  789. } else {
  790. nOffset = 1;
  791. nStopAt = GETNUMBUTTONS(hwnd);
  792. }
  793. /* look for next button that isn't grayed */
  794. /* DON'T wrap around - future code will pass */
  795. /* the focus to another window (???) */
  796. for (iBtnPos = GETWHICH(hwnd) + nOffset;
  797. iBtnPos != nStopAt;
  798. iBtnPos += nOffset) {
  799. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  800. if (toolbarStateFromButton(hwnd, iButton) !=
  801. BTNST_GRAYED) {
  802. SETWHICH(hwnd, iBtnPos); // set focus
  803. /* Redraw both old and new focused button */
  804. toolbarRectFromIndex(hwnd, iPrevPos, &rc);
  805. InvalidateRect(hwnd, &rc, FALSE);
  806. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  807. InvalidateRect(hwnd, &rc, FALSE);
  808. break;
  809. }
  810. }
  811. if (GETWHICH(hwnd) != iPrevPos)
  812. return TRUE;
  813. else
  814. return FALSE;
  815. }
  816. /***************************************************************************/
  817. /* toolbarSetFocus : Set the focus in the toolbar to the specified button.*/
  818. /* If it's gray, it'll set focus to next ungrayed btn. */
  819. /* Returns TRUE if focus set, or FALSE if the button */
  820. /* doesn't exist or if it and all buttons after it were */
  821. /* grayed... You can use TB_FIRST or TB_LAST in */
  822. /* place of a button ID. This uses the first or last */
  823. /* un-grayed button. */
  824. /***************************************************************************/
  825. BOOL FAR PASCAL toolbarSetFocus(HWND hwnd, int iButton)
  826. {
  827. int iBtnPos;
  828. RECT rc;
  829. /* Don't move focus while a button is down */
  830. if (GetCapture() != hwnd && !GETKEYPRESSED(hwnd)) {
  831. /* redraw button with focus in case focus moves */
  832. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  833. InvalidateRect(hwnd, &rc, FALSE);
  834. if (iButton == TB_FIRST) {
  835. SETWHICH(hwnd, -1); // move forward to 1st button
  836. return toolbarMoveFocus(hwnd, FALSE);
  837. } else if (iButton == TB_LAST) {
  838. SETWHICH(hwnd, GETNUMBUTTONS(hwnd));
  839. return toolbarMoveFocus(hwnd, TRUE);
  840. } else {
  841. iBtnPos = toolbarIndexFromButton(hwnd, iButton);
  842. if (iBtnPos != -1) {
  843. SETWHICH(hwnd, --iBtnPos);
  844. return toolbarMoveFocus(hwnd, FALSE);
  845. } else
  846. return FALSE;
  847. }
  848. return TRUE;
  849. } else
  850. return FALSE;
  851. }
  852. //
  853. // LoadUIBitmap() - load a bitmap resource
  854. //
  855. // load a bitmap resource from a resource file, converting all
  856. // the standard UI colors to the current user specifed ones.
  857. //
  858. // this code is designed to load bitmaps used in "gray ui" or
  859. // "toolbar" code.
  860. //
  861. // the bitmap must be a 4bpp windows 3.0 DIB, with the standard
  862. // VGA 16 colors.
  863. //
  864. // the bitmap must be authored with the following colors
  865. //
  866. // Button Text Black (index 0)
  867. // Button Face lt gray (index 7)
  868. // Button Shadow gray (index 8)
  869. // Button Highlight white (index 15)
  870. // Window Color yellow (index 11)
  871. // Window Frame green (index 10)
  872. //
  873. // Example:
  874. //
  875. // hbm = LoadUIBitmap(hInstance, "TestBmp",
  876. // GetSysColor(COLOR_BTNTEXT),
  877. // GetSysColor(COLOR_BTNFACE),
  878. // GetSysColor(COLOR_BTNSHADOW),
  879. // GetSysColor(COLOR_BTNHIGHLIGHT),
  880. // GetSysColor(COLOR_WINDOW),
  881. // GetSysColor(COLOR_WINDOWFRAME));
  882. //
  883. // Author: JimBov, ToddLa
  884. //
  885. //
  886. HBITMAP FAR PASCAL LoadUIBitmap(
  887. HANDLE hInstance, // EXE file to load resource from
  888. LPCSTR szName, // name of bitmap resource
  889. COLORREF rgbText, // color to use for "Button Text"
  890. COLORREF rgbFace, // color to use for "Button Face"
  891. COLORREF rgbShadow, // color to use for "Button Shadow"
  892. COLORREF rgbHighlight, // color to use for "Button Hilight"
  893. COLORREF rgbWindow, // color to use for "Window Color"
  894. COLORREF rgbFrame) // color to use for "Window Frame"
  895. {
  896. LPBYTE lpb;
  897. HBITMAP hbm;
  898. LPBITMAPINFOHEADER lpbi;
  899. HANDLE h;
  900. HDC hdc;
  901. LPDWORD lprgb;
  902. int isize;
  903. HANDLE hmem;
  904. LPBYTE lpCopy;
  905. // convert a RGB into a RGBQ
  906. #define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw))
  907. h = LoadResource (hInstance,FindResource(hInstance, szName, RT_BITMAP));
  908. lpbi = (LPBITMAPINFOHEADER)LockResource(h);
  909. if (!lpbi)
  910. return(NULL);
  911. if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
  912. return NULL;
  913. if (lpbi->biBitCount != 4)
  914. return NULL;
  915. /*
  916. * copy the resource since they are now loaded read-only
  917. */
  918. #ifdef _WIN32
  919. isize = lpbi->biSize + lpbi->biSizeImage +
  920. ((int)lpbi->biClrUsed ?
  921. (int)lpbi->biClrUsed :
  922. (1 << (int)lpbi->biBitCount))
  923. * sizeof(RGBQUAD);
  924. hmem = GlobalAlloc(GHND, isize);
  925. lpCopy = GlobalLock(hmem);
  926. if ((hmem == NULL) || (lpCopy == NULL)) {
  927. UnlockResource(h);
  928. FreeResource(h);
  929. return(NULL);
  930. }
  931. CopyMemory(lpCopy, lpbi, isize);
  932. UnlockResource(h);
  933. FreeResource(h);
  934. lpbi = (LPBITMAPINFOHEADER)lpCopy;
  935. #endif
  936. /* Calcluate the pointer to the Bits information */
  937. /* First skip over the header structure */
  938. lprgb = (LPDWORD)((LPBYTE)(lpbi) + lpbi->biSize);
  939. /* Skip the color table entries, if any */
  940. lpb = (LPBYTE)lprgb + ((int)lpbi->biClrUsed ? (int)lpbi->biClrUsed :
  941. (1 << (int)lpbi->biBitCount)) * sizeof(RGBQUAD);
  942. lprgb[0] = RGBQ(rgbText); // Black
  943. lprgb[7] = RGBQ(rgbFace); // lt gray
  944. lprgb[8] = RGBQ(rgbShadow); // gray
  945. lprgb[15] = RGBQ(rgbHighlight); // white
  946. lprgb[11] = RGBQ(rgbWindow); // yellow
  947. lprgb[10] = RGBQ(rgbFrame); // green
  948. hdc = GetDC(NULL);
  949. hbm = CreateDIBitmap (hdc, lpbi, CBM_INIT, (LPVOID)lpb,
  950. (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  951. ReleaseDC(NULL, hdc);
  952. UnlockResource(h);
  953. FreeResource(h);
  954. return(hbm);
  955. }
  956. /****************************************************************************
  957. toolbarWndProc()
  958. Window proc for toolbar.
  959. Arguments:
  960. Standard window proc
  961. ****************************************************************************/
  962. LONG FAR PASCAL toolbarWndProc(HWND hwnd, unsigned message,
  963. UINT wParam, LONG lParam)
  964. {
  965. PAINTSTRUCT ps;
  966. POINT pt;
  967. RECT rc;
  968. int iBtnPos, iButton, ibmp;
  969. HANDLE lpaButtons, hbm, hInst;
  970. switch (message) {
  971. case WM_CREATE: // do all initialization
  972. /* What do these do? */
  973. SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  974. SWP_NOZORDER | SWP_NOSIZE |
  975. SWP_NOMOVE | SWP_NOACTIVATE);
  976. SetWindowLong(hwnd,GWL_STYLE,lpCreate->style & 0xFFFF00FF);
  977. /* Alloc some space for the array of buttons on this bar */
  978. lpaButtons = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  979. TOOLGROW * sizeof(TOOLBUTTON));
  980. SETARRAYBUTT(hwnd, lpaButtons); // list of buttons on toolbar
  981. SETNUMBUTTONS(hwnd, 0); // # buttons in toolbar
  982. SETPRESSED(hwnd, FALSE); // mouse button being pressed?
  983. SETKEYPRESSED(hwnd, FALSE); // is a key being pressed?
  984. SETWHICH(hwnd, -1); // which button has the focus?
  985. SETSHIFTED(hwnd, FALSE); // shift-click or right-click?
  986. /* This wParam will be sent to the parent window to indentify */
  987. /* that the toolbar sent the WM_COMMAND msg. The hwnd of the */
  988. /* toolbar that sent the msg will be in the lParam. */
  989. #ifdef _WIN32
  990. SetWindowLong(hwnd, GWL_ID, IDC_TOOLBAR);
  991. #else
  992. SetWindowWord(hwnd, GWW_ID, (WORD)IDC_TOOLBAR);
  993. #endif
  994. /* later on, someone will set the bmp handle of the buttons */
  995. SETBMPHANDLE(hwnd, NULL);
  996. break;
  997. case WM_LBUTTONDOWN: // button goes down on a toolbar button
  998. case WM_RBUTTONDOWN:
  999. case WM_LBUTTONDBLCLK:
  1000. case WM_RBUTTONDBLCLK:
  1001. /* If we don't give ourself focus, we'll never get KEYDOWN */
  1002. /* or KEYUP messages. */
  1003. /* Get the focus only if we're a TABSTOP and the app wants */
  1004. /* us to take focus. */
  1005. if ( (GetWindowLong(hwnd, GWL_STYLE) & WS_TABSTOP)
  1006. && GetFocus() != hwnd)
  1007. SetFocus(hwnd);
  1008. /* ignore messages if window is disabled */
  1009. if (!IsWindowEnabled(hwnd))
  1010. return 0L;
  1011. /* ignore multiple down messages (we set Capture here) */
  1012. /* also ignore if a key is down */
  1013. if (GetCapture() == hwnd || GETPRESSED(hwnd))
  1014. return 0L;
  1015. /* Where did the mouse go down? */
  1016. pt.x = (short)LOWORD(lParam);
  1017. pt.y = (short)HIWORD(lParam);
  1018. /* which button was pressed? */
  1019. iBtnPos = toolbarIndexFromPoint(hwnd, pt);
  1020. /* If it was a valid button... */
  1021. if (iBtnPos >= 0) {
  1022. int iOldPos;
  1023. int iState, iType, iButton;
  1024. /* Everything you wanted to know about this button */
  1025. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1026. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1027. iState = toolbarFullStateFromButton(hwnd, iButton);
  1028. /* ignore downs on a grayed button, unless it's a */
  1029. /* custom button, then tell them anyway */
  1030. if (iType != BTNTYPE_CUSTOM && iState == BTNST_GRAYED)
  1031. return 0;
  1032. /* We better get all mouse messages from now on */
  1033. SetCapture(hwnd);
  1034. /* Shift key or right button indicates a SHIFT down */
  1035. SETSHIFTED(hwnd, (message == WM_RBUTTONDOWN) ||
  1036. (wParam & MK_SHIFT));
  1037. /* Yes, we've pressed the button down */
  1038. SETPRESSED(hwnd, TRUE);
  1039. /* Remember who used to have the focus, and we get it now */
  1040. iOldPos = GETWHICH(hwnd);
  1041. SETWHICH(hwnd, iBtnPos);
  1042. /* For a push button, send it down */
  1043. if (iType == BTNTYPE_PUSH)
  1044. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1045. /* for a checkbox or radio button (of any group), */
  1046. /* remember what state it was in, and send it FULL down */
  1047. /* (with focus). */
  1048. if (iType == BTNTYPE_CHECKBOX || iType >= BTNTYPE_RADIO) {
  1049. toolbarModifyPrevState(hwnd, iButton, iState);
  1050. toolbarModifyState(hwnd,iButton,BTNST_FULLDOWN);
  1051. }
  1052. toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEDOWN);
  1053. /* Set Double click flag appropriately */
  1054. if (message == WM_LBUTTONDBLCLK ||
  1055. message == WM_RBUTTONDBLCLK)
  1056. NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0)
  1057. + BTN_DBLCLICK + iButton);
  1058. else
  1059. NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0)
  1060. + iButton);
  1061. /* Invalidate the Rect of the button being pressed */
  1062. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1063. InvalidateRect(hwnd, &rc, FALSE);
  1064. /* Invalidate the Rect of the button losing focus */
  1065. toolbarRectFromIndex(hwnd, iOldPos, &rc);
  1066. InvalidateRect(hwnd, &rc, FALSE);
  1067. /* Force re-paint now */
  1068. UpdateWindow(hwnd);
  1069. /* Set a timer for repeated mouse downs */
  1070. SetTimer(hwnd, TIMER_BUTTONREPEAT,
  1071. MSEC_BUTTONREPEAT, NULL);
  1072. }
  1073. return 0L;
  1074. case WM_MOUSEMOVE:
  1075. #if 0
  1076. /* This should be impossible - it means that the system lost */
  1077. /* a mouse up (maybe codeview is up?) We need to force a */
  1078. /* mouse up at this point. */
  1079. if (GetCapture() == hwnd &&
  1080. (wParam & (MK_LBUTTON | MK_RBUTTON) == 0))
  1081. SendMessage(hwnd, WM_LBUTTONUP, 0, lParam);
  1082. #endif
  1083. /* Mouse moving while pressing a button? If not, ignore. */
  1084. if (GetCapture() == hwnd) {
  1085. int iPrevState, iState, iButton, iType;
  1086. BOOL fPressed;
  1087. /* Which button is being pressed down? */
  1088. iBtnPos = GETWHICH(hwnd);
  1089. /* Where is mouse cursor now? */
  1090. pt.x = (short)LOWORD(lParam);
  1091. pt.y = (short)HIWORD(lParam);
  1092. /* where is button being pressed? Are we still on */
  1093. /* top of that button or have we moved? */
  1094. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1095. fPressed = PtInRect(&rc, pt);
  1096. /* Let go if we move off of the button, but don't */
  1097. /* act like it was pressed. */
  1098. /* Also, push it back down if we move back on top */
  1099. /* of it (while the mouse button is STILL down). */
  1100. if (fPressed != GETPRESSED(hwnd)) {
  1101. /* update: is this button pressed anymore? */
  1102. SETPRESSED(hwnd, fPressed);
  1103. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1104. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1105. iState = toolbarFullStateFromButton(hwnd, iButton);
  1106. /* The mouse moved back onto the button while */
  1107. /* the mouse button was still pressed. */
  1108. if (fPressed) {
  1109. /* Push the push button back down again */
  1110. if (iType == BTNTYPE_PUSH)
  1111. toolbarModifyState(hwnd, iButton,
  1112. BTNST_DOWN);
  1113. /* Push the radio or checkbox button ALL the */
  1114. /* way down again. */
  1115. if (iType >= BTNTYPE_RADIO ||
  1116. iType == BTNTYPE_CHECKBOX)
  1117. toolbarModifyState(hwnd, iButton,
  1118. BTNST_FULLDOWN);
  1119. toolbarModifyActivity(hwnd, iButton,
  1120. BTNACT_MOUSEMOVEON);
  1121. NotifyParent(hwnd,
  1122. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1123. iButton);
  1124. /* We moved the mouse off of the toolbar button */
  1125. /* while still holding the mouse button down. */
  1126. } else {
  1127. /* lift the push button up */
  1128. if (iType == BTNTYPE_PUSH)
  1129. toolbarModifyState(hwnd, iButton,
  1130. BTNST_UP);
  1131. /* Restore radio button or checkbox button to */
  1132. /* where it was before pressed */
  1133. if (iType >= BTNTYPE_RADIO ||
  1134. iType == BTNTYPE_CHECKBOX) {
  1135. iPrevState = toolbarPrevStateFromButton(hwnd,
  1136. iButton);
  1137. toolbarModifyState(hwnd, iButton, iPrevState);
  1138. }
  1139. toolbarModifyActivity(hwnd, iButton,
  1140. BTNACT_MOUSEMOVEOFF);
  1141. NotifyParent(hwnd,
  1142. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1143. toolbarButtonFromIndex(hwnd, iBtnPos));
  1144. }
  1145. }
  1146. }
  1147. return 0L;
  1148. case WM_LBUTTONUP:
  1149. case WM_RBUTTONUP:
  1150. /* If we don't have capture, we aren't expecting this. Ignore */
  1151. if (GetCapture() == hwnd) {
  1152. int iPrevState, iState, iButton, iType;
  1153. /* Who has the focus? */
  1154. iBtnPos = GETWHICH(hwnd);
  1155. /* Release the mouse */
  1156. ReleaseCapture();
  1157. /* No more repeats of the mouse button downs */
  1158. KillTimer(hwnd, TIMER_BUTTONREPEAT);
  1159. /* Everything you wanted to know about the button */
  1160. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1161. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1162. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1163. iState = toolbarFullStateFromButton(hwnd, iButton);
  1164. /* Don't do anything if we've moved off the button */
  1165. if (GETPRESSED(hwnd)) {
  1166. /* No longer down */
  1167. SETPRESSED(hwnd, FALSE);
  1168. /* Bring the push button up */
  1169. if (iType == BTNTYPE_PUSH)
  1170. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1171. /* Bring the checkbox to the opposite state it was in */
  1172. if (iType == BTNTYPE_CHECKBOX) {
  1173. iPrevState = toolbarPrevStateFromButton(hwnd,
  1174. iButton);
  1175. if (iPrevState == BTNST_DOWN)
  1176. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1177. if (iPrevState == BTNST_UP)
  1178. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1179. }
  1180. /* Force a radio button down, and bring all */
  1181. /* other radio buttons of this type up */
  1182. if (iType >= BTNTYPE_RADIO) {
  1183. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1184. toolbarExclusiveRadio(hwnd, iType, iButton);
  1185. }
  1186. /* Notify the parent that the mouse button came up */
  1187. /* on this button so the app can do something. */
  1188. /* Every button should notify the app, not just a */
  1189. /* custom button. */
  1190. toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEUP);
  1191. NotifyParent(hwnd,
  1192. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton);
  1193. }
  1194. }
  1195. return 0L;
  1196. case WM_TIMER:
  1197. /* If we have a tool button down, send a repeat message */
  1198. if (GETPRESSED(hwnd)) {
  1199. int iButton, iType;
  1200. iBtnPos = GETWHICH(hwnd);
  1201. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1202. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1203. NotifyParent(hwnd, BTN_REPEAT +
  1204. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1205. toolbarButtonFromIndex(hwnd, iBtnPos));
  1206. }
  1207. break;
  1208. case WM_DESTROY:
  1209. if (GETBMPHANDLE(hwnd))
  1210. DeleteObject(GETBMPHANDLE(hwnd));
  1211. SETBMPHANDLE(hwnd, NULL);
  1212. if (GETARRAYBUTT(hwnd))
  1213. GlobalFree(GETARRAYBUTT(hwnd));
  1214. SETARRAYBUTT(hwnd, NULL);
  1215. break;
  1216. case WM_SETTEXT:
  1217. break;
  1218. /* MANY, MANY cases deleted */
  1219. case WM_SETFOCUS: // focus comes to toolbar window
  1220. {
  1221. /* Remember who had the focus and give it back. Of course, */
  1222. /* if by some wierdness that button is now grayed, give it */
  1223. /* to the next person in line. */
  1224. iBtnPos = GETWHICH(hwnd);
  1225. if (iBtnPos < 0 || iBtnPos >= toolbarGetNumButtons(hwnd)) {
  1226. iBtnPos = 0;
  1227. SETWHICH(hwnd, 0);
  1228. }
  1229. do {
  1230. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1231. if (toolbarFullStateFromButton(hwnd, iButton)
  1232. != BTNST_GRAYED)
  1233. break; // give it here
  1234. iBtnPos++;
  1235. if (iBtnPos >= toolbarGetNumButtons(hwnd))
  1236. iBtnPos = 0; // wrap around
  1237. if (iBtnPos == GETWHICH(hwnd))
  1238. return 0L; // uh-oh! They're all gray!
  1239. } while (iBtnPos != GETWHICH(hwnd));
  1240. SETWHICH(hwnd, iBtnPos); // give focus here
  1241. /* And redraw! */
  1242. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1243. InvalidateRect(hwnd, &rc, FALSE);
  1244. UpdateWindow(hwnd);
  1245. return 0;
  1246. }
  1247. case WM_KILLFOCUS:
  1248. /* Send a KEYUP if one is pending */
  1249. if (GETKEYPRESSED(hwnd))
  1250. SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L);
  1251. /* Redraw the focused button, because now that focus is gone */
  1252. /* from our toolbar window, the focused button won't be */
  1253. /* focused anymore, although we remember which one it was. */
  1254. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1255. InvalidateRect(hwnd, &rc, FALSE);
  1256. UpdateWindow(hwnd);
  1257. return 0;
  1258. case WM_SYSKEYDOWN:
  1259. /* Send a KEYUP if one is pending */
  1260. if (GETKEYPRESSED(hwnd))
  1261. SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L);
  1262. break; // MUST LET DEFWNDPROC RUN!!! (to handle the key)
  1263. case WM_GETDLGCODE:
  1264. return DLGC_WANTARROWS | DLGC_WANTTAB;
  1265. case WM_KEYDOWN:
  1266. /* Window disabled or a key is already down */
  1267. if (IsWindowEnabled(hwnd) && !GETPRESSED(hwnd)) {
  1268. /* Tab forward to next button and move focus there */
  1269. if (wParam == VK_TAB && GetKeyState(VK_SHIFT) >= 0 ) {
  1270. /* Move Focus forward one. If */
  1271. /* we've tabbed off of the toolbar, it's time */
  1272. /* to go on to the next control. We need to invldte */
  1273. /* because we might be the only control and we need */
  1274. /* to repaint to show the new button with highlight */
  1275. /* after it wrapped around the end of the toolbar. */
  1276. if (!toolbarMoveFocus(hwnd, FALSE)) {
  1277. PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 0, 0L);
  1278. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1279. InvalidateRect(hwnd, &rc, FALSE);
  1280. }
  1281. return 0L;
  1282. }
  1283. if (wParam == VK_TAB && GetKeyState(VK_SHIFT) < 0 ) {
  1284. /* Move focus backward one. If */
  1285. /* We've tabbed off of the toolbar, it's time */
  1286. /* to go on to the next control. We need to invldte */
  1287. /* because we might be the only control and we need */
  1288. /* to repaint to show the new button with highlight */
  1289. /* after it wrapped around the end of the toolbar. */
  1290. if (!toolbarMoveFocus(hwnd, TRUE)) {
  1291. PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 1, 0L);
  1292. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1293. InvalidateRect(hwnd, &rc, FALSE);
  1294. }
  1295. return 0L;
  1296. }
  1297. if ((wParam == VK_SPACE) && (GetCapture() != hwnd)) {
  1298. int iButton, iType, iState;
  1299. /* Same as mouse button down -- Press the button! */
  1300. iBtnPos = GETWHICH(hwnd);
  1301. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1302. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1303. iState = toolbarFullStateFromButton(hwnd, iButton);
  1304. /* ignore multiple key downs */
  1305. if (!GETKEYPRESSED(hwnd)) {
  1306. SETKEYPRESSED(hwnd, TRUE); // a key is pressed
  1307. SETSHIFTED(hwnd, FALSE); // NEVER shifted
  1308. SETPRESSED(hwnd, TRUE); // a button is pressed
  1309. /* Push button goes down - with focus */
  1310. if (iType == BTNTYPE_PUSH)
  1311. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1312. /* Radio or checkbox button goes full down */
  1313. /* with focus - and remember previous state*/
  1314. if (iType >= BTNTYPE_RADIO ||
  1315. iType == BTNTYPE_CHECKBOX) {
  1316. toolbarModifyPrevState(hwnd, iButton, iState);
  1317. toolbarModifyState(hwnd, iButton,
  1318. BTNST_FULLDOWN);
  1319. }
  1320. toolbarModifyActivity(hwnd, iButton,
  1321. BTNACT_KEYDOWN);
  1322. NotifyParent(hwnd, (GETSHIFTED(hwnd)
  1323. ? BTN_SHIFT : 0) + iButton);
  1324. return 0L;
  1325. }
  1326. /* If this is another KEYDOWN msg, it's a REPEAT */
  1327. /* Notify parent. */
  1328. NotifyParent(hwnd, BTN_REPEAT +
  1329. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1330. toolbarButtonFromIndex(hwnd,
  1331. GETWHICH(hwnd)));
  1332. }
  1333. }
  1334. break;
  1335. case WM_KEYUP:
  1336. /* A button was pressed and should come up now */
  1337. if ((wParam == VK_SPACE) && (GETKEYPRESSED(hwnd))) {
  1338. int iButton, iState, iType, iPrevState;
  1339. iBtnPos = GETWHICH(hwnd); // which button?
  1340. SETKEYPRESSED(hwnd, FALSE); // let go
  1341. SETPRESSED(hwnd, FALSE);
  1342. /* Everything about this button */
  1343. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1344. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1345. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1346. iState = toolbarFullStateFromButton(hwnd, iButton);
  1347. /* Bring a push button up */
  1348. if (iType == BTNTYPE_PUSH)
  1349. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1350. /* Bring a checkbox to the opposite state it was in */
  1351. if (iType == BTNTYPE_CHECKBOX) {
  1352. iPrevState = toolbarPrevStateFromButton(hwnd, iButton);
  1353. if (iPrevState == BTNST_DOWN)
  1354. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1355. if (iPrevState == BTNST_UP)
  1356. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1357. }
  1358. /* Bring a radio button down, and bring all others in */
  1359. /* its group up. */
  1360. if (iType >= BTNTYPE_RADIO) {
  1361. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1362. toolbarExclusiveRadio(hwnd, iType, iButton);
  1363. }
  1364. toolbarModifyActivity(hwnd, iButton, BTNACT_KEYUP);
  1365. NotifyParent(hwnd, toolbarButtonFromIndex(hwnd,
  1366. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1367. GETWHICH(hwnd)));
  1368. }
  1369. break;
  1370. case WM_SYSCOLORCHANGE:
  1371. /* load the bitmap of what all the buttons look like */
  1372. /* and change the colours to the system colours. */
  1373. hInst = GETHINST(hwnd);
  1374. ibmp = GETBMPINT(hwnd);
  1375. hbm = GETBMPHANDLE(hwnd);
  1376. if (hbm)
  1377. DeleteObject(hbm);
  1378. hbm = LoadUIBitmap(hInst, MAKEINTRESOURCE(ibmp),
  1379. GetSysColor(COLOR_BTNTEXT),
  1380. GetSysColor(COLOR_BTNFACE),
  1381. GetSysColor(COLOR_BTNSHADOW),
  1382. GetSysColor(COLOR_BTNHIGHLIGHT),
  1383. GetSysColor(COLOR_BTNFACE),
  1384. GetSysColor(COLOR_WINDOWFRAME));
  1385. SETBMPHANDLE(hwnd, hbm);
  1386. #ifdef _WIN32
  1387. return (long) hbm;
  1388. #else
  1389. return MAKELONG(hbm, 0);
  1390. #endif
  1391. case WM_ERASEBKGND:
  1392. break;
  1393. case WM_PAINT:
  1394. /* Call our paint code */
  1395. BeginPaint(hwnd, &ps);
  1396. toolbarPaintControl(hwnd, ps.hdc);
  1397. EndPaint(hwnd, &ps);
  1398. return 0L;
  1399. }
  1400. return DefWindowProc(hwnd, message, wParam, lParam);
  1401. }