Leaked source code of windows server 2003
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.

1742 lines
55 KiB

  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. TCHAR szToolBarClass[] = "ToolBarClass";
  29. HBRUSH ghbrToolbar; // brush for toolbar background
  30. //
  31. // Window proc for buttons, THIS FUNCTION MUST BE EXPORTED
  32. //
  33. LRESULT FAR PASCAL toolbarWndProc(HWND, unsigned, WPARAM, LPARAM);
  34. typedef long (FAR PASCAL *LPWNDPROC)();
  35. /*
  36. Defines
  37. */
  38. #ifdef _WIN32
  39. #define GETARRAYBUTT(hwnd) ((HANDLE)GetWindowLongPtr(hwnd,GWLP_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)GetWindowLongPtr(hwnd,GWLP_BMPHANDLE))
  46. #define GETBMPINT(hwnd) ((int)GetWindowLong(hwnd,GWL_BMPINT))
  47. #define GETBUTTONSIZE(hwnd) GetWindowLong(hwnd,GWL_BUTTONSIZE)
  48. #define GETHINST(hwnd) ((HANDLE)GetWindowLongPtr(hwnd,GWLP_HINST))
  49. #define SETARRAYBUTT(hwnd, h) SetWindowLongPtr(hwnd, GWLP_ARRAYBUTT, (UINT_PTR)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) SetWindowLongPtr(hwnd, GWLP_BMPHANDLE, (UINT_PTR)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) SetWindowLongPtr(hwnd, GWLP_HINST, (UINT_PTR)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 = {0};
  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 = NULL;
  898. LPBITMAPINFOHEADER lpbi;
  899. HANDLE h;
  900. HDC hdc;
  901. LPDWORD lprgb;
  902. int isize;
  903. HANDLE hmem;
  904. LPBYTE lpCopy;
  905. HRSRC hRes;
  906. // convert a RGB into a RGBQ
  907. #define RGBQ(dw) RGB(GetBValue(dw),GetGValue(dw),GetRValue(dw))
  908. hRes = FindResource(hInstance, szName, RT_BITMAP);
  909. if (NULL == hRes) {
  910. return NULL;
  911. }
  912. if ( !(h = LoadResource (hInstance,hRes) ) )
  913. return NULL;
  914. lpbi = (LPBITMAPINFOHEADER)LockResource(h);
  915. if (!lpbi)
  916. return(NULL);
  917. if (lpbi->biSize != sizeof(BITMAPINFOHEADER))
  918. return NULL;
  919. if (lpbi->biBitCount != 4)
  920. return NULL;
  921. /*
  922. * copy the resource since they are now loaded read-only
  923. */
  924. #ifdef _WIN32
  925. isize = lpbi->biSize + lpbi->biSizeImage +
  926. ((int)lpbi->biClrUsed ?
  927. (int)lpbi->biClrUsed :
  928. (1 << (int)lpbi->biBitCount))
  929. * sizeof(RGBQUAD);
  930. hmem = GlobalAlloc(GHND, isize);
  931. lpCopy = GlobalLock(hmem);
  932. if ((hmem == NULL) || (lpCopy == NULL)) {
  933. UnlockResource(h);
  934. FreeResource(h);
  935. return(NULL);
  936. }
  937. CopyMemory(lpCopy, lpbi, isize);
  938. lpbi = (LPBITMAPINFOHEADER)lpCopy;
  939. #endif
  940. /* Calcluate the pointer to the Bits information */
  941. /* First skip over the header structure */
  942. lprgb = (LPDWORD)((LPBYTE)(lpbi) + lpbi->biSize);
  943. /* Skip the color table entries, if any */
  944. lpb = (LPBYTE)lprgb + ((int)lpbi->biClrUsed ? (int)lpbi->biClrUsed :
  945. (1 << (int)lpbi->biBitCount)) * sizeof(RGBQUAD);
  946. lprgb[0] = RGBQ(rgbText); // Black
  947. lprgb[7] = RGBQ(rgbFace); // lt gray
  948. lprgb[8] = RGBQ(rgbShadow); // gray
  949. lprgb[15] = RGBQ(rgbHighlight); // white
  950. lprgb[11] = RGBQ(rgbWindow); // yellow
  951. lprgb[10] = RGBQ(rgbFrame); // green
  952. if ( hdc = GetDC(NULL) )
  953. {
  954. hbm = CreateDIBitmap (hdc, lpbi, CBM_INIT, (LPVOID)lpb,
  955. (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
  956. ReleaseDC(NULL, hdc);
  957. }
  958. UnlockResource(h);
  959. FreeResource(h);
  960. return(hbm);
  961. }
  962. /****************************************************************************
  963. toolbarWndProc()
  964. Window proc for toolbar.
  965. Arguments:
  966. Standard window proc
  967. ****************************************************************************/
  968. LRESULT FAR PASCAL toolbarWndProc(HWND hwnd, unsigned message,
  969. WPARAM wParam, LPARAM lParam)
  970. {
  971. PAINTSTRUCT ps;
  972. POINT pt;
  973. RECT rc;
  974. int iBtnPos, iButton, ibmp;
  975. HANDLE lpaButtons, hbm, hInst;
  976. switch (message) {
  977. case WM_CREATE: // do all initialization
  978. /* What do these do? */
  979. SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
  980. SWP_NOZORDER | SWP_NOSIZE |
  981. SWP_NOMOVE | SWP_NOACTIVATE);
  982. SetWindowLong(hwnd,GWL_STYLE,lpCreate->style & 0xFFFF00FF);
  983. /* Alloc some space for the array of buttons on this bar */
  984. lpaButtons = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
  985. TOOLGROW * sizeof(TOOLBUTTON));
  986. SETARRAYBUTT(hwnd, lpaButtons); // list of buttons on toolbar
  987. SETNUMBUTTONS(hwnd, 0); // # buttons in toolbar
  988. SETPRESSED(hwnd, FALSE); // mouse button being pressed?
  989. SETKEYPRESSED(hwnd, FALSE); // is a key being pressed?
  990. SETWHICH(hwnd, -1); // which button has the focus?
  991. SETSHIFTED(hwnd, FALSE); // shift-click or right-click?
  992. /* This wParam will be sent to the parent window to indentify */
  993. /* that the toolbar sent the WM_COMMAND msg. The hwnd of the */
  994. /* toolbar that sent the msg will be in the lParam. */
  995. #ifdef _WIN32
  996. SetWindowLong(hwnd, GWL_ID, IDC_TOOLBAR);
  997. #else
  998. SetWindowWord(hwnd, GWW_ID, (WORD)IDC_TOOLBAR);
  999. #endif
  1000. /* later on, someone will set the bmp handle of the buttons */
  1001. SETBMPHANDLE(hwnd, NULL);
  1002. break;
  1003. case WM_LBUTTONDOWN: // button goes down on a toolbar button
  1004. case WM_RBUTTONDOWN:
  1005. case WM_LBUTTONDBLCLK:
  1006. case WM_RBUTTONDBLCLK:
  1007. /* If we don't give ourself focus, we'll never get KEYDOWN */
  1008. /* or KEYUP messages. */
  1009. /* Get the focus only if we're a TABSTOP and the app wants */
  1010. /* us to take focus. */
  1011. if ( (GetWindowLong(hwnd, GWL_STYLE) & WS_TABSTOP)
  1012. && GetFocus() != hwnd)
  1013. SetFocus(hwnd);
  1014. /* ignore messages if window is disabled */
  1015. if (!IsWindowEnabled(hwnd))
  1016. return 0L;
  1017. /* ignore multiple down messages (we set Capture here) */
  1018. /* also ignore if a key is down */
  1019. if (GetCapture() == hwnd || GETPRESSED(hwnd))
  1020. return 0L;
  1021. /* Where did the mouse go down? */
  1022. pt.x = (short)LOWORD(lParam);
  1023. pt.y = (short)HIWORD(lParam);
  1024. /* which button was pressed? */
  1025. iBtnPos = toolbarIndexFromPoint(hwnd, pt);
  1026. /* If it was a valid button... */
  1027. if (iBtnPos >= 0) {
  1028. int iOldPos;
  1029. int iState, iType, iButton;
  1030. /* Everything you wanted to know about this button */
  1031. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1032. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1033. iState = toolbarFullStateFromButton(hwnd, iButton);
  1034. /* ignore downs on a grayed button, unless it's a */
  1035. /* custom button, then tell them anyway */
  1036. if (iType != BTNTYPE_CUSTOM && iState == BTNST_GRAYED)
  1037. return 0;
  1038. /* We better get all mouse messages from now on */
  1039. SetCapture(hwnd);
  1040. /* Shift key or right button indicates a SHIFT down */
  1041. SETSHIFTED(hwnd, (message == WM_RBUTTONDOWN) ||
  1042. (wParam & MK_SHIFT));
  1043. /* Yes, we've pressed the button down */
  1044. SETPRESSED(hwnd, TRUE);
  1045. /* Remember who used to have the focus, and we get it now */
  1046. iOldPos = GETWHICH(hwnd);
  1047. SETWHICH(hwnd, iBtnPos);
  1048. /* For a push button, send it down */
  1049. if (iType == BTNTYPE_PUSH)
  1050. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1051. /* for a checkbox or radio button (of any group), */
  1052. /* remember what state it was in, and send it FULL down */
  1053. /* (with focus). */
  1054. if (iType == BTNTYPE_CHECKBOX || iType >= BTNTYPE_RADIO) {
  1055. toolbarModifyPrevState(hwnd, iButton, iState);
  1056. toolbarModifyState(hwnd,iButton,BTNST_FULLDOWN);
  1057. }
  1058. toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEDOWN);
  1059. /* Set Double click flag appropriately */
  1060. if (message == WM_LBUTTONDBLCLK ||
  1061. message == WM_RBUTTONDBLCLK)
  1062. NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0)
  1063. + BTN_DBLCLICK + iButton);
  1064. else
  1065. NotifyParent(hwnd, (GETSHIFTED(hwnd) ? BTN_SHIFT : 0)
  1066. + iButton);
  1067. /* Invalidate the Rect of the button being pressed */
  1068. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1069. InvalidateRect(hwnd, &rc, FALSE);
  1070. /* Invalidate the Rect of the button losing focus */
  1071. toolbarRectFromIndex(hwnd, iOldPos, &rc);
  1072. InvalidateRect(hwnd, &rc, FALSE);
  1073. /* Force re-paint now */
  1074. UpdateWindow(hwnd);
  1075. /* Set a timer for repeated mouse downs */
  1076. SetTimer(hwnd, TIMER_BUTTONREPEAT,
  1077. MSEC_BUTTONREPEAT, NULL);
  1078. }
  1079. return 0L;
  1080. case WM_MOUSEMOVE:
  1081. #if 0
  1082. /* This should be impossible - it means that the system lost */
  1083. /* a mouse up (maybe codeview is up?) We need to force a */
  1084. /* mouse up at this point. */
  1085. if (GetCapture() == hwnd &&
  1086. (wParam & (MK_LBUTTON | MK_RBUTTON) == 0))
  1087. SendMessage(hwnd, WM_LBUTTONUP, 0, lParam);
  1088. #endif
  1089. /* Mouse moving while pressing a button? If not, ignore. */
  1090. if (GetCapture() == hwnd) {
  1091. int iPrevState, iState, iButton, iType;
  1092. BOOL fPressed;
  1093. /* Which button is being pressed down? */
  1094. iBtnPos = GETWHICH(hwnd);
  1095. /* Where is mouse cursor now? */
  1096. pt.x = (short)LOWORD(lParam);
  1097. pt.y = (short)HIWORD(lParam);
  1098. /* where is button being pressed? Are we still on */
  1099. /* top of that button or have we moved? */
  1100. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1101. fPressed = PtInRect(&rc, pt);
  1102. /* Let go if we move off of the button, but don't */
  1103. /* act like it was pressed. */
  1104. /* Also, push it back down if we move back on top */
  1105. /* of it (while the mouse button is STILL down). */
  1106. if (fPressed != GETPRESSED(hwnd)) {
  1107. /* update: is this button pressed anymore? */
  1108. SETPRESSED(hwnd, fPressed);
  1109. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1110. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1111. iState = toolbarFullStateFromButton(hwnd, iButton);
  1112. /* The mouse moved back onto the button while */
  1113. /* the mouse button was still pressed. */
  1114. if (fPressed) {
  1115. /* Push the push button back down again */
  1116. if (iType == BTNTYPE_PUSH)
  1117. toolbarModifyState(hwnd, iButton,
  1118. BTNST_DOWN);
  1119. /* Push the radio or checkbox button ALL the */
  1120. /* way down again. */
  1121. if (iType >= BTNTYPE_RADIO ||
  1122. iType == BTNTYPE_CHECKBOX)
  1123. toolbarModifyState(hwnd, iButton,
  1124. BTNST_FULLDOWN);
  1125. toolbarModifyActivity(hwnd, iButton,
  1126. BTNACT_MOUSEMOVEON);
  1127. NotifyParent(hwnd,
  1128. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1129. iButton);
  1130. /* We moved the mouse off of the toolbar button */
  1131. /* while still holding the mouse button down. */
  1132. } else {
  1133. /* lift the push button up */
  1134. if (iType == BTNTYPE_PUSH)
  1135. toolbarModifyState(hwnd, iButton,
  1136. BTNST_UP);
  1137. /* Restore radio button or checkbox button to */
  1138. /* where it was before pressed */
  1139. if (iType >= BTNTYPE_RADIO ||
  1140. iType == BTNTYPE_CHECKBOX) {
  1141. iPrevState = toolbarPrevStateFromButton(hwnd,
  1142. iButton);
  1143. toolbarModifyState(hwnd, iButton, iPrevState);
  1144. }
  1145. toolbarModifyActivity(hwnd, iButton,
  1146. BTNACT_MOUSEMOVEOFF);
  1147. NotifyParent(hwnd,
  1148. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1149. toolbarButtonFromIndex(hwnd, iBtnPos));
  1150. }
  1151. }
  1152. }
  1153. return 0L;
  1154. case WM_LBUTTONUP:
  1155. case WM_RBUTTONUP:
  1156. /* If we don't have capture, we aren't expecting this. Ignore */
  1157. if (GetCapture() == hwnd) {
  1158. int iPrevState, iState, iButton, iType;
  1159. /* Who has the focus? */
  1160. iBtnPos = GETWHICH(hwnd);
  1161. /* Release the mouse */
  1162. ReleaseCapture();
  1163. /* No more repeats of the mouse button downs */
  1164. KillTimer(hwnd, TIMER_BUTTONREPEAT);
  1165. /* Everything you wanted to know about the button */
  1166. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1167. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1168. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1169. iState = toolbarFullStateFromButton(hwnd, iButton);
  1170. /* Don't do anything if we've moved off the button */
  1171. if (GETPRESSED(hwnd)) {
  1172. /* No longer down */
  1173. SETPRESSED(hwnd, FALSE);
  1174. /* Bring the push button up */
  1175. if (iType == BTNTYPE_PUSH)
  1176. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1177. /* Bring the checkbox to the opposite state it was in */
  1178. if (iType == BTNTYPE_CHECKBOX) {
  1179. iPrevState = toolbarPrevStateFromButton(hwnd,
  1180. iButton);
  1181. if (iPrevState == BTNST_DOWN)
  1182. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1183. if (iPrevState == BTNST_UP)
  1184. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1185. }
  1186. /* Force a radio button down, and bring all */
  1187. /* other radio buttons of this type up */
  1188. if (iType >= BTNTYPE_RADIO) {
  1189. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1190. toolbarExclusiveRadio(hwnd, iType, iButton);
  1191. }
  1192. /* Notify the parent that the mouse button came up */
  1193. /* on this button so the app can do something. */
  1194. /* Every button should notify the app, not just a */
  1195. /* custom button. */
  1196. toolbarModifyActivity(hwnd, iButton, BTNACT_MOUSEUP);
  1197. NotifyParent(hwnd,
  1198. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) + iButton);
  1199. }
  1200. }
  1201. return 0L;
  1202. case WM_TIMER:
  1203. /* If we have a tool button down, send a repeat message */
  1204. if (GETPRESSED(hwnd)) {
  1205. int iButton, iType;
  1206. iBtnPos = GETWHICH(hwnd);
  1207. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1208. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1209. NotifyParent(hwnd, BTN_REPEAT +
  1210. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1211. toolbarButtonFromIndex(hwnd, iBtnPos));
  1212. }
  1213. break;
  1214. case WM_DESTROY:
  1215. if (GETBMPHANDLE(hwnd))
  1216. DeleteObject(GETBMPHANDLE(hwnd));
  1217. SETBMPHANDLE(hwnd, NULL);
  1218. if (GETARRAYBUTT(hwnd))
  1219. GlobalFree(GETARRAYBUTT(hwnd));
  1220. SETARRAYBUTT(hwnd, NULL);
  1221. break;
  1222. case WM_SETTEXT:
  1223. break;
  1224. /* MANY, MANY cases deleted */
  1225. case WM_SETFOCUS: // focus comes to toolbar window
  1226. {
  1227. /* Remember who had the focus and give it back. Of course, */
  1228. /* if by some wierdness that button is now grayed, give it */
  1229. /* to the next person in line. */
  1230. iBtnPos = GETWHICH(hwnd);
  1231. if (iBtnPos < 0 || iBtnPos >= toolbarGetNumButtons(hwnd)) {
  1232. iBtnPos = 0;
  1233. SETWHICH(hwnd, 0);
  1234. }
  1235. do {
  1236. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1237. if (toolbarFullStateFromButton(hwnd, iButton)
  1238. != BTNST_GRAYED)
  1239. break; // give it here
  1240. iBtnPos++;
  1241. if (iBtnPos >= toolbarGetNumButtons(hwnd))
  1242. iBtnPos = 0; // wrap around
  1243. if (iBtnPos == GETWHICH(hwnd))
  1244. return 0L; // uh-oh! They're all gray!
  1245. } while (iBtnPos != GETWHICH(hwnd));
  1246. SETWHICH(hwnd, iBtnPos); // give focus here
  1247. /* And redraw! */
  1248. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1249. InvalidateRect(hwnd, &rc, FALSE);
  1250. UpdateWindow(hwnd);
  1251. return 0;
  1252. }
  1253. case WM_KILLFOCUS:
  1254. /* Send a KEYUP if one is pending */
  1255. if (GETKEYPRESSED(hwnd))
  1256. SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L);
  1257. /* Redraw the focused button, because now that focus is gone */
  1258. /* from our toolbar window, the focused button won't be */
  1259. /* focused anymore, although we remember which one it was. */
  1260. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1261. InvalidateRect(hwnd, &rc, FALSE);
  1262. UpdateWindow(hwnd);
  1263. return 0;
  1264. case WM_SYSKEYDOWN:
  1265. /* Send a KEYUP if one is pending */
  1266. if (GETKEYPRESSED(hwnd))
  1267. SendMessage(hwnd, WM_KEYUP, VK_SPACE, 0L);
  1268. break; // MUST LET DEFWNDPROC RUN!!! (to handle the key)
  1269. case WM_GETDLGCODE:
  1270. return DLGC_WANTARROWS | DLGC_WANTTAB;
  1271. case WM_KEYDOWN:
  1272. /* Window disabled or a key is already down */
  1273. if (IsWindowEnabled(hwnd) && !GETPRESSED(hwnd)) {
  1274. /* Tab forward to next button and move focus there */
  1275. if (wParam == VK_TAB && GetKeyState(VK_SHIFT) >= 0 ) {
  1276. /* Move Focus forward one. If */
  1277. /* we've tabbed off of the toolbar, it's time */
  1278. /* to go on to the next control. We need to invldte */
  1279. /* because we might be the only control and we need */
  1280. /* to repaint to show the new button with highlight */
  1281. /* after it wrapped around the end of the toolbar. */
  1282. if (!toolbarMoveFocus(hwnd, FALSE)) {
  1283. PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 0, 0L);
  1284. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1285. InvalidateRect(hwnd, &rc, FALSE);
  1286. }
  1287. return 0L;
  1288. }
  1289. if (wParam == VK_TAB && GetKeyState(VK_SHIFT) < 0 ) {
  1290. /* Move focus backward one. If */
  1291. /* We've tabbed off of the toolbar, it's time */
  1292. /* to go on to the next control. We need to invldte */
  1293. /* because we might be the only control and we need */
  1294. /* to repaint to show the new button with highlight */
  1295. /* after it wrapped around the end of the toolbar. */
  1296. if (!toolbarMoveFocus(hwnd, TRUE)) {
  1297. PostMessage(GetParent(hwnd), WM_NEXTDLGCTL, 1, 0L);
  1298. toolbarRectFromIndex(hwnd, GETWHICH(hwnd), &rc);
  1299. InvalidateRect(hwnd, &rc, FALSE);
  1300. }
  1301. return 0L;
  1302. }
  1303. if ((wParam == VK_SPACE) && (GetCapture() != hwnd)) {
  1304. int iButton, iType, iState;
  1305. /* Same as mouse button down -- Press the button! */
  1306. iBtnPos = GETWHICH(hwnd);
  1307. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1308. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1309. iState = toolbarFullStateFromButton(hwnd, iButton);
  1310. /* ignore multiple key downs */
  1311. if (!GETKEYPRESSED(hwnd)) {
  1312. SETKEYPRESSED(hwnd, TRUE); // a key is pressed
  1313. SETSHIFTED(hwnd, FALSE); // NEVER shifted
  1314. SETPRESSED(hwnd, TRUE); // a button is pressed
  1315. /* Push button goes down - with focus */
  1316. if (iType == BTNTYPE_PUSH)
  1317. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1318. /* Radio or checkbox button goes full down */
  1319. /* with focus - and remember previous state*/
  1320. if (iType >= BTNTYPE_RADIO ||
  1321. iType == BTNTYPE_CHECKBOX) {
  1322. toolbarModifyPrevState(hwnd, iButton, iState);
  1323. toolbarModifyState(hwnd, iButton,
  1324. BTNST_FULLDOWN);
  1325. }
  1326. toolbarModifyActivity(hwnd, iButton,
  1327. BTNACT_KEYDOWN);
  1328. NotifyParent(hwnd, (GETSHIFTED(hwnd)
  1329. ? BTN_SHIFT : 0) + iButton);
  1330. return 0L;
  1331. }
  1332. /* If this is another KEYDOWN msg, it's a REPEAT */
  1333. /* Notify parent. */
  1334. NotifyParent(hwnd, BTN_REPEAT +
  1335. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1336. toolbarButtonFromIndex(hwnd,
  1337. GETWHICH(hwnd)));
  1338. }
  1339. }
  1340. break;
  1341. case WM_KEYUP:
  1342. /* A button was pressed and should come up now */
  1343. if ((wParam == VK_SPACE) && (GETKEYPRESSED(hwnd))) {
  1344. int iButton, iState, iType, iPrevState;
  1345. iBtnPos = GETWHICH(hwnd); // which button?
  1346. SETKEYPRESSED(hwnd, FALSE); // let go
  1347. SETPRESSED(hwnd, FALSE);
  1348. /* Everything about this button */
  1349. toolbarRectFromIndex(hwnd, iBtnPos, &rc);
  1350. iType = toolbarTypeFromIndex(hwnd, iBtnPos);
  1351. iButton = toolbarButtonFromIndex(hwnd, iBtnPos);
  1352. iState = toolbarFullStateFromButton(hwnd, iButton);
  1353. /* Bring a push button up */
  1354. if (iType == BTNTYPE_PUSH)
  1355. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1356. /* Bring a checkbox to the opposite state it was in */
  1357. if (iType == BTNTYPE_CHECKBOX) {
  1358. iPrevState = toolbarPrevStateFromButton(hwnd, iButton);
  1359. if (iPrevState == BTNST_DOWN)
  1360. toolbarModifyState(hwnd, iButton, BTNST_UP);
  1361. if (iPrevState == BTNST_UP)
  1362. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1363. }
  1364. /* Bring a radio button down, and bring all others in */
  1365. /* its group up. */
  1366. if (iType >= BTNTYPE_RADIO) {
  1367. toolbarModifyState(hwnd, iButton, BTNST_DOWN);
  1368. toolbarExclusiveRadio(hwnd, iType, iButton);
  1369. }
  1370. toolbarModifyActivity(hwnd, iButton, BTNACT_KEYUP);
  1371. NotifyParent(hwnd, toolbarButtonFromIndex(hwnd,
  1372. (GETSHIFTED(hwnd) ? BTN_SHIFT : 0) +
  1373. GETWHICH(hwnd)));
  1374. }
  1375. break;
  1376. case WM_SYSCOLORCHANGE:
  1377. /* load the bitmap of what all the buttons look like */
  1378. /* and change the colours to the system colours. */
  1379. hInst = GETHINST(hwnd);
  1380. ibmp = GETBMPINT(hwnd);
  1381. hbm = GETBMPHANDLE(hwnd);
  1382. if (hbm)
  1383. DeleteObject(hbm);
  1384. hbm = LoadUIBitmap(hInst, MAKEINTRESOURCE(ibmp),
  1385. GetSysColor(COLOR_BTNTEXT),
  1386. GetSysColor(COLOR_BTNFACE),
  1387. GetSysColor(COLOR_BTNSHADOW),
  1388. GetSysColor(COLOR_BTNHIGHLIGHT),
  1389. GetSysColor(COLOR_BTNFACE),
  1390. GetSysColor(COLOR_WINDOWFRAME));
  1391. SETBMPHANDLE(hwnd, hbm);
  1392. #ifdef _WIN32
  1393. return (LONG_PTR) hbm;
  1394. #else
  1395. return MAKELONG(hbm, 0);
  1396. #endif
  1397. case WM_ERASEBKGND:
  1398. break;
  1399. case WM_PAINT:
  1400. /* Call our paint code */
  1401. BeginPaint(hwnd, &ps);
  1402. toolbarPaintControl(hwnd, ps.hdc);
  1403. EndPaint(hwnd, &ps);
  1404. return 0L;
  1405. }
  1406. return DefWindowProc(hwnd, message, wParam, lParam);
  1407. }