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.

766 lines
20 KiB

  1. /*
  2. * GIZMO.C
  3. * GizmoBar Version 1.00, Win32 version August 1993
  4. *
  5. * Allocate, free, find, and enumerate functions for the GIZMO structure
  6. * and a generic subclass procedure to handle tabbing between gizmos.
  7. *
  8. * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  9. *
  10. * Kraig Brockschmidt, Software Design Engineer
  11. * Microsoft Systems Developer Relations
  12. *
  13. * Internet : kraigb@microsoft.com
  14. * Compuserve: >INTERNET:kraigb@microsoft.com
  15. */
  16. #include <windows.h>
  17. #include "gizmoint.h"
  18. /*
  19. * In order to control tabbing in the gizmos, we need to subclass
  20. * real pushbuttons, edit controls, listboxes, and comboboxes. So
  21. * we keep an array of the four original procs for such controls.
  22. */
  23. WNDPROC pfnOrg[CSUBGIZMOS]={NULL, NULL, NULL, NULL};
  24. TCHAR szStatic[]=TEXT("static");
  25. TCHAR szEdit[]=TEXT("edit");
  26. TCHAR szCombobox[]=TEXT("combobox");
  27. TCHAR szListbox[]=TEXT("listbox");
  28. TCHAR szButton[]=TEXT("button");
  29. //Here so PAINT.C can get at it.
  30. TOOLDISPLAYDATA tdd;
  31. /*
  32. * GizmoPAllocate
  33. *
  34. * Purpose:
  35. * Allocates and initializes a GIZMO data structure.
  36. *
  37. * Parameters:
  38. * pfSuccess LPINT flag indicating success of failure.
  39. * ppFirst LPLPGIZMO providing the first gizmo in this list.
  40. * hWndParent HWND of the parent of this gizmo. Can be NULL for
  41. * iType==GIZMOTYPE_BUTTON* or GIZMOTYPE_SEPARATOR.
  42. * iType UINT gizmo control type.
  43. * iGizmo UINT index of this gizmo in the GizmoBar.
  44. * uID UINT identifier to send with WM_COMMAND for this control.
  45. * dx, dy UINT width and height of the gizmo.
  46. * pszText LPTSTR to the text for edits, listboxes, combobox, and text.
  47. * dwStyle DWORD style for edits, lists, and combos, and texts.
  48. * hBmp HBITMAP for button gizmos, is applicable.
  49. * iImage UINT index into hBmp for the button image, if applicable.
  50. * uState UINT initial state of the control.
  51. *
  52. * Return Value:
  53. * LPGIZMO If NULL returned then GizmoPAllocate could not allocate
  54. * memory. If a non-NULL pointer is returned with
  55. * *pfSuccess, then call GizmoPFree immediately. If you
  56. * get a non-NULL pointer and *pfSuccess==TRUE then the
  57. * function succeeded.
  58. */
  59. LPGIZMO GizmoPAllocate(LPINT pfSuccess, LPLPGIZMO ppFirst, HWND hWndParent
  60. , UINT iType, UINT iGizmo, UINT uID, UINT dx, UINT dy, LPTSTR pszText
  61. , HBITMAP hBmp, UINT iImage, UINT uState)
  62. {
  63. LPGIZMO pGizmo;
  64. LPGIZMO pCur, pPrev;
  65. LPTSTR pszClass;
  66. HINSTANCE hInst;
  67. UINT i;
  68. DWORD dwStyle;
  69. HWND hWndE;
  70. if (NULL==pfSuccess)
  71. return NULL;
  72. //Make sure we know of this gizmo type.
  73. if (GIZMOTYPE_MIN > iType || GIZMOTYPE_MAX < iType)
  74. return NULL;
  75. *pfSuccess=FALSE;
  76. //Allocate the structure
  77. pGizmo=(LPGIZMO)LocalAlloc(LPTR, CBGIZMO);
  78. if (NULL==pGizmo)
  79. return NULL;
  80. //Store the necessary information for this gizmo.
  81. pGizmo->iType =iType;
  82. pGizmo->uID =uID;
  83. pGizmo->hBmp =hBmp;
  84. pGizmo->iBmp =iImage;
  85. pGizmo->uState =uState;
  86. pGizmo->fNotify =TRUE;
  87. /*
  88. * Insert this structure into our gizmo list. Each time we scan
  89. * we increment the index counter (starting at zero) comparing it
  90. * to the desired index of insertion. We then know exactly where
  91. * to insert this new gizmo. Note that we insert the new gizmo in
  92. * the list appropriately for the given owner, so enumerations will
  93. * come out ordered in the same way for that owner.
  94. */
  95. i=0;
  96. pCur=*ppFirst;
  97. pPrev=NULL;
  98. while (NULL!=pCur && i++ < iGizmo)
  99. {
  100. pPrev=pCur;
  101. pCur =pCur->pNext;
  102. }
  103. //Point to our neighbors
  104. pGizmo->pPrev=pPrev;
  105. pGizmo->pNext=pCur;
  106. //Point out neighbors to us.
  107. if (NULL==pPrev)
  108. *ppFirst=pGizmo;
  109. else
  110. pPrev->pNext=pGizmo;
  111. if (NULL!=pCur)
  112. pCur->pPrev=pGizmo;
  113. //Our x-coordinate is the x of the previous gizmo plus its width.
  114. if (NULL!=pPrev)
  115. pGizmo->x=pGizmo->pPrev->x+pGizmo->pPrev->dx;
  116. else
  117. pGizmo->x=4; //First gizmo is at x=4
  118. //If we're a separator or image button, force standards on dx.
  119. UIToolConfigureForDisplay(&tdd);
  120. pGizmo->cxImage=tdd.cxImage;
  121. pGizmo->cyImage=tdd.cyImage;
  122. if ((GIZMOTYPE_DRAWN & iType) && NULL==hBmp)
  123. dx=tdd.cxButton;
  124. if (GIZMOTYPE_SEPARATOR==iType)
  125. dx=6;
  126. /*
  127. * Now create windows for edits, texts, lists, and comboboxes.
  128. * First calculate the most often defaults used in the switch.
  129. */
  130. pGizmo->dx=dx+6;
  131. pGizmo->dy=min(dy, tdd.cyButton);
  132. pGizmo->y=2;
  133. pszClass=NULL;
  134. //If this is new gizmo is a window, create it.
  135. switch (iType)
  136. {
  137. case GIZMOTYPE_TEXT:
  138. pGizmo->dx=dx;
  139. pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1; //Center vertically.
  140. pszClass=szStatic;
  141. dwStyle=SS_LEFT;
  142. break;
  143. case GIZMOTYPE_EDIT:
  144. pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1; //Center vertically.
  145. pszClass=szEdit;
  146. dwStyle=ES_LEFT | WS_BORDER | WS_TABSTOP;
  147. break;
  148. case GIZMOTYPE_LISTBOX:
  149. pGizmo->dy=dy;
  150. pszClass=szCombobox;
  151. dwStyle=CBS_DROPDOWNLIST | WS_TABSTOP;
  152. break;
  153. case GIZMOTYPE_COMBOBOX:
  154. pGizmo->dy=dy;
  155. pszClass=szCombobox;
  156. dwStyle=CBS_DROPDOWN | WS_TABSTOP;
  157. break;
  158. case GIZMOTYPE_BUTTONNORMAL:
  159. pGizmo->dy=dy;
  160. pszClass=szButton;
  161. dwStyle=BS_PUSHBUTTON | WS_TABSTOP;
  162. break;
  163. case GIZMOTYPE_SEPARATOR:
  164. pGizmo->dx=dx;
  165. pGizmo->y=3;
  166. break;
  167. case GIZMOTYPE_BUTTONATTRIBUTEIN:
  168. case GIZMOTYPE_BUTTONATTRIBUTEEX:
  169. case GIZMOTYPE_BUTTONCOMMAND:
  170. pGizmo->dx=dx;
  171. pGizmo->y=3;
  172. break;
  173. }
  174. //If we matched a classname, create a window.
  175. if (GIZMOTYPE_WINDOWS & iType)
  176. {
  177. if (!IsWindow(hWndParent))
  178. return pGizmo;
  179. hInst=(HINSTANCE) GetWindowLongPtr(hWndParent, GWLP_HINSTANCE);
  180. pGizmo->hWnd=CreateWindow(pszClass, pszText
  181. , dwStyle | WS_CHILD | WS_VISIBLE, pGizmo->x, pGizmo->y
  182. , dx, pGizmo->dy, hWndParent, (HMENU)uID, hInst, NULL);
  183. if (NULL==pGizmo->hWnd)
  184. return pGizmo;
  185. /*
  186. * Subclass comboboxes, listboxes, edits, and windowed buttons.
  187. * We use iType to index the original proc array so we can use
  188. * a single subclass procedure for all controls. If you mess
  189. * with the gizmo type definitions, this is going to break.
  190. */
  191. if (GIZMOTYPE_WINDOWS & iType && GIZMOTYPE_TEXT!=iType)
  192. {
  193. //Give the window its type.
  194. BITPOSITION(iType, i);
  195. SetProp(pGizmo->hWnd, SZTYPEPROP, (HANDLE)i);
  196. if (NULL==pfnOrg[i])
  197. pfnOrg[i]=(WNDPROC)GetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC);
  198. SetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC, (LONG_PTR)GenericSubProc);
  199. //If we're a combobox, get the edit control and subclass it.
  200. if (GIZMOTYPE_COMBOBOX==iType)
  201. {
  202. hWndE=GetDlgItem(pGizmo->hWnd, ID_COMBOEDIT);
  203. SetProp(hWndE, SZTYPEPROP, (HANDLE)-1); //Special flag.
  204. if (NULL==pfnOrg[0])
  205. pfnOrg[0]=(WNDPROC)GetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC);
  206. SetWindowLongPtr(hWndE, GWLP_WNDPROC, (LONG_PTR)GenericSubProc);
  207. }
  208. }
  209. }
  210. //Finally, move all our neighbors to the right over to accomodate us.
  211. GizmosExpand(pGizmo);
  212. *pfSuccess=TRUE;
  213. return pGizmo;
  214. }
  215. /*
  216. * GizmoPFree
  217. *
  218. * Purpose:
  219. * Reverses all initialization done by GizmoPAllocate, cleaning up
  220. * any allocations including the application structure itself.
  221. *
  222. * Parameters:
  223. * ppFirst LPLPGIZMO providing the first gizmo in this list.
  224. * pGizmo LPGIZMO to the structure
  225. *
  226. * Return Value:
  227. * LPGIZMO NULL if successful, pGizmo if not, meaning we couldn't
  228. * free something.
  229. */
  230. LPGIZMO GizmoPFree(LPLPGIZMO ppFirst, LPGIZMO pGizmo)
  231. {
  232. int i;
  233. if (NULL==pGizmo)
  234. return NULL;
  235. //Move other gizmos to fill in this gap.
  236. GizmosCompact(pGizmo);
  237. //Unsubclass
  238. if (GIZMOTYPE_WINDOWS & pGizmo->iType && GIZMOTYPE_TEXT!=pGizmo->iType)
  239. {
  240. i=(int)GetProp(pGizmo->hWnd, SZTYPEPROP);
  241. RemoveProp(pGizmo->hWnd, SZTYPEPROP);
  242. SetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC, (LONG_PTR)pfnOrg[i]);
  243. }
  244. //If this was a window gizmo, destroy the window.
  245. if (NULL!=pGizmo->hWnd && IsWindow(pGizmo->hWnd))
  246. DestroyWindow(pGizmo->hWnd);
  247. //Unlink ourselves.
  248. if (NULL!=pGizmo->pNext)
  249. pGizmo->pNext->pPrev=pGizmo->pPrev;
  250. if (NULL!=pGizmo->pPrev)
  251. pGizmo->pPrev->pNext=pGizmo->pNext;
  252. else
  253. *ppFirst=pGizmo->pNext;
  254. return (LPGIZMO)LocalFree((HLOCAL)(UINT)(LONG)pGizmo);
  255. }
  256. /*
  257. * GizmosExpand
  258. *
  259. * Purpose:
  260. * Given a starting gizmo and a width, moves it and all gizmos to its
  261. * right to the right by the width to make space for showing or creating
  262. * a new gizmo.
  263. *
  264. * Parameters:
  265. * pGizmo LPGIZMO specifying the gizmo that was inserted.
  266. *
  267. * Return Value:
  268. * None
  269. */
  270. void GizmosExpand(LPGIZMO pGizmo)
  271. {
  272. int cx;
  273. cx=(int)pGizmo->dx;
  274. /*
  275. * If we and the next control are buttons, use our width-1 to
  276. * expand so we overlap borders with our neighboring button.
  277. */
  278. if (NULL!=pGizmo->pNext)
  279. {
  280. if ((GIZMOTYPE_BUTTONS & pGizmo->pNext->iType)
  281. && (GIZMOTYPE_BUTTONS & pGizmo->iType))
  282. cx-=1;
  283. }
  284. //Walk the gizmo list moving them right by our width.
  285. pGizmo=pGizmo->pNext;
  286. while (NULL!=pGizmo)
  287. {
  288. pGizmo->x+=cx;
  289. //hWnd is NULL for buttons and separators.
  290. if (NULL!=pGizmo->hWnd)
  291. SetWindowPos(pGizmo->hWnd, NULL, pGizmo->x, pGizmo->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  292. pGizmo=pGizmo->pNext;
  293. }
  294. return;
  295. }
  296. /*
  297. * GizmosCompact
  298. *
  299. * Purpose:
  300. * Given a gizmo, moves all other gizmos to the right of it to the
  301. * left by its width on the GizmoBar. Used when removing or hiding
  302. * the gizmo.
  303. *
  304. * Parameters:
  305. * pGizmo LPGIZMO that is going away, visibly or physically.
  306. *
  307. * Return Value:
  308. * None
  309. */
  310. void GizmosCompact(LPGIZMO pGizmo)
  311. {
  312. UINT cx;
  313. LPGIZMO pCur;
  314. //Move all the gizmos beyond us on the GizmoBar back by our width.
  315. if (NULL!=pGizmo->pNext)
  316. {
  317. cx=pGizmo->pNext->x - pGizmo->x;
  318. pCur=pGizmo->pNext;
  319. while (NULL!=pCur)
  320. {
  321. pCur->x-=cx;
  322. if (NULL!=pCur->hWnd)
  323. {
  324. SetWindowPos(pCur->hWnd, NULL, pCur->x, pCur->y
  325. , 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  326. }
  327. pCur=pCur->pNext;
  328. }
  329. }
  330. return;
  331. }
  332. /*
  333. * GizmoPFind
  334. *
  335. * Purpose:
  336. * Given a GIZMO identifier, locates and returns a pointer to the structure
  337. * for that position.
  338. *
  339. * Parameters:
  340. * ppFirst LPLPGIZMO providing the first gizmo in this list.
  341. * uID UINT identifier to find.
  342. *
  343. * Return Value:
  344. * LPGIZMO A pointer to a GIZMO structure allocated through
  345. * GizmoPAllocate, NULL if iGizmo is out of range.
  346. */
  347. LPGIZMO GizmoPFind(LPLPGIZMO ppFirst, UINT uID)
  348. {
  349. LPGIZMO pGizmo;
  350. pGizmo=*ppFirst;
  351. /*
  352. * Yep, linear search, but a better search algorithm won't improve
  353. * things appreciably. The better thing to optimize is what the
  354. * caller passes as ppFirst.
  355. */
  356. while (NULL!=pGizmo && uID!=pGizmo->uID)
  357. pGizmo=pGizmo->pNext;
  358. return pGizmo;
  359. }
  360. /*
  361. * GizmoFEnum
  362. *
  363. * Purpose:
  364. * Enumerates the list of GIZMO structures, passing each one to
  365. * an application-defined callback.
  366. *
  367. * Parameters:
  368. * ppFirst LPLPGIZMO providing the first gizmo in this list.
  369. * pfnEnum LPFNGIZMOENUM to call for each enumerated structure.
  370. * dw DWORD extra data to pass to the enumeration function.
  371. *
  372. * Return Value:
  373. * LPGIZMO NULL if the enumeration completed. Otherwise a pointer
  374. * to the gizmo that enumeration stopped on.
  375. */
  376. LPGIZMO GizmoPEnum(LPLPGIZMO ppFirst, LPFNGIZMOENUM pfnEnum, DWORD dw)
  377. {
  378. LPGIZMO pGizmo;
  379. UINT i=0;
  380. pGizmo=*ppFirst;
  381. while (NULL!=pGizmo)
  382. {
  383. if (!(*pfnEnum)(pGizmo, i++, dw))
  384. break;
  385. pGizmo=pGizmo->pNext;
  386. }
  387. return pGizmo;
  388. }
  389. /*
  390. * GizmoPStateSet
  391. *
  392. * Purpose:
  393. * State maniuplation functions. Set and Clear also invalidate
  394. * this gizmo's rectangle on the given window and forces a repaint.
  395. *
  396. * Parameters:
  397. * hWnd HWND of the window to repaint.
  398. * pGizmo LPGIZMO affected.
  399. * dwNew DWORD new state flags.
  400. *
  401. * Return Value:
  402. * UINT Previous state.
  403. */
  404. UINT GizmoPStateSet(HWND hWnd, LPGIZMO pGizmo, UINT uNew)
  405. {
  406. UINT uRet;
  407. RECT rc;
  408. if (GIZMOTYPE_SEPARATOR==pGizmo->iType)
  409. return pGizmo->uState;
  410. //Preserve the color conversion flags across this state change.
  411. uRet=pGizmo->uState;
  412. pGizmo->uState=(uNew & 0x00FF) | (uRet & 0xFF00);
  413. //Adjust the rectangle by one to avoid repainting borders.
  414. SetRect(&rc, pGizmo->x+1, pGizmo->y+1, pGizmo->x+pGizmo->dx-1, pGizmo->y+pGizmo->dy-1);
  415. InvalidateRect(hWnd, &rc, FALSE);
  416. UpdateWindow(hWnd);
  417. return uRet;
  418. }
  419. /*
  420. * GizmoPCheck
  421. *
  422. * Purpose:
  423. * Handles checking a single button in a group of attribute buttons.
  424. * If the gizmo belongs to a group of mutually exclusive buttons then
  425. * the others surrounding it are unchecked appropriately.
  426. *
  427. * Parameters:
  428. * hWnd HWND of the GizmoBar.
  429. * pGizmo LPGIZMO of the gizmo affected.
  430. * fCheck BOOL TRUE to check the button, FALSE to uncheck.
  431. *
  432. * Return Value:
  433. * BOOL TRUE if the gizmo was previously checked, FALSE
  434. * otherwise.
  435. */
  436. BOOL GizmoPCheck(HWND hWnd, LPGIZMO pGizmo, BOOL fCheck)
  437. {
  438. BOOL fPrevCheck;
  439. LPGIZMO pCur;
  440. //Ignore command buttons.
  441. if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType)
  442. return FALSE;
  443. //Get the previous state
  444. fPrevCheck=(BOOL)(BUTTONGROUP_DOWN & pGizmo->uState);
  445. //Simply set the state for inclusive attribute buttons.
  446. if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType)
  447. {
  448. if (pGizmo->fDisabled)
  449. {
  450. GizmoPStateSet(hWnd, pGizmo
  451. , fCheck ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DISABLED);
  452. }
  453. else
  454. {
  455. GizmoPStateSet(hWnd, pGizmo
  456. , fCheck ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_UP);
  457. }
  458. }
  459. if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType)
  460. {
  461. //We cannot uncheck an exclusive attribute
  462. if (!fCheck)
  463. return fPrevCheck;
  464. /*
  465. * For exclusive buttons we have to do more work. First, if we're
  466. * already checked (incliding DOWN and MOUSEDOWN) then we set DOWN
  467. * and exit. If we're not already checked, then we look for the
  468. * gizmo around us, backwards and forwards, that is checked and
  469. * uncheck him.
  470. */
  471. //Search backwards.
  472. pCur=pGizmo->pPrev;
  473. while (NULL!=pCur)
  474. {
  475. //Stop at any non-exclusive attribute.
  476. if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)
  477. {
  478. pCur=NULL;
  479. break;
  480. }
  481. //If it's down, set it up and we've finished.
  482. if (BUTTONGROUP_DOWN & pCur->uState)
  483. break;
  484. pCur=pCur->pPrev;
  485. }
  486. //If we didn't find a previous one, pCur is NULL, so look ahead.
  487. if (NULL==pCur)
  488. {
  489. pCur=pGizmo->pNext;
  490. while (NULL!=pCur)
  491. {
  492. //Stop at any non-exclusive attribute.
  493. if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)
  494. {
  495. pCur=NULL;
  496. break;
  497. }
  498. //If it's down, set it up and we've finished.
  499. if (BUTTONGROUP_DOWN & pCur->uState)
  500. break;
  501. pCur=pCur->pNext;
  502. }
  503. }
  504. //If pCur is non-NULL, the we found a neighbor, so uncheck him
  505. if (NULL!=pCur)
  506. {
  507. GizmoPStateSet(hWnd, pCur
  508. , (pGizmo->fDisabled) ? ATTRIBUTEBUTTON_DISABLED : ATTRIBUTEBUTTON_UP);
  509. }
  510. //Always set ourselves down
  511. GizmoPStateSet(hWnd, pGizmo
  512. , (pGizmo->fDisabled) ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DOWN);
  513. }
  514. return fPrevCheck;
  515. }
  516. /*
  517. * GenericSubProc
  518. *
  519. * Purpose:
  520. * Subclasses window controls in Gizmos so we can trap the tab key and
  521. * tab to the next control. We can have one shared generic subclass
  522. * procedure because we save the type index for this control in the
  523. * property "iType." This allows us to look up the original procedure
  524. * in the pfnOrg array.
  525. *
  526. * Parameters:
  527. * Standard
  528. *
  529. * Return Value:
  530. * Standard
  531. */
  532. //LRESULT FAR PASCAL EXPORT GenericSubProc(HWND hWnd, UINT iMsg
  533. LRESULT FAR PASCAL GenericSubProc(HWND hWnd, UINT iMsg
  534. , WPARAM wParam, LPARAM lParam)
  535. {
  536. LRESULT lRet;
  537. RECT rc;
  538. RECT rcE;
  539. HWND hWndE;
  540. HBRUSH hBr;
  541. HDC hDC;
  542. UINT dx;
  543. UINT iType, i;
  544. i=(int)GetProp(hWnd, SZTYPEPROP);
  545. iType=POSITIONBIT(i);
  546. //Special: paint the gap in drop-down comboboxes.
  547. if (GIZMOTYPE_COMBOBOX==iType && WM_PAINT==iMsg)
  548. {
  549. //Do default painting.
  550. lRet=(*pfnOrg[i])(hWnd, iMsg, wParam, lParam);
  551. hWndE=GetDlgItem(hWnd, ID_COMBOEDIT);
  552. GetClientRect(hWnd, &rc);
  553. GetClientRect(hWndE, &rcE);
  554. //The width of the button is the scroll bar width.
  555. dx=GetSystemMetrics(SM_CXVSCROLL);
  556. //Calculate the rectangle
  557. rc.right -=dx;
  558. rc.left =rcE.right;
  559. rc.bottom+=1;
  560. //Paint the gap
  561. hDC=GetDC(hWnd); //Already did BeginPaint and EndPaint
  562. hBr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
  563. FillRect(hDC, &rc, hBr);
  564. DeleteObject(hBr);
  565. ReleaseDC(hWnd, hDC);
  566. return lRet;
  567. }
  568. //Control tabbing to the next or previous control in the GizmoBar.
  569. if (WM_KEYDOWN==iMsg && VK_TAB==wParam)
  570. {
  571. hWndE=hWnd;
  572. if (-1==i)
  573. hWndE=GetParent(hWnd);
  574. hWndE=GetNextDlgTabItem(GetParent(hWndE), hWnd, (BOOL)(GetKeyState(VK_SHIFT)));
  575. SetFocus(hWndE);
  576. return 0L;
  577. }
  578. if (-1==i) i=0;
  579. //Eat tab chars in edit controls to prevent beeping.
  580. if (0==i && WM_CHAR==iMsg && VK_TAB==wParam)
  581. return 0L;
  582. //Do this or edit controls bomb big-time.
  583. return CallWindowProc(pfnOrg[i], hWnd, iMsg, wParam, lParam);
  584. }