summaryrefslogtreecommitdiffstats
path: root/private/oleutest/letest/gizmobar/gizmo.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/oleutest/letest/gizmobar/gizmo.c')
-rw-r--r--private/oleutest/letest/gizmobar/gizmo.c766
1 files changed, 766 insertions, 0 deletions
diff --git a/private/oleutest/letest/gizmobar/gizmo.c b/private/oleutest/letest/gizmobar/gizmo.c
new file mode 100644
index 000000000..c763c3bba
--- /dev/null
+++ b/private/oleutest/letest/gizmobar/gizmo.c
@@ -0,0 +1,766 @@
+/*
+ * GIZMO.C
+ * GizmoBar Version 1.00, Win32 version August 1993
+ *
+ * Allocate, free, find, and enumerate functions for the GIZMO structure
+ * and a generic subclass procedure to handle tabbing between gizmos.
+ *
+ * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
+ *
+ * Kraig Brockschmidt, Software Design Engineer
+ * Microsoft Systems Developer Relations
+ *
+ * Internet : kraigb@microsoft.com
+ * Compuserve: >INTERNET:kraigb@microsoft.com
+ */
+
+
+#include <windows.h>
+#include "gizmoint.h"
+
+
+/*
+ * In order to control tabbing in the gizmos, we need to subclass
+ * real pushbuttons, edit controls, listboxes, and comboboxes. So
+ * we keep an array of the four original procs for such controls.
+ */
+WNDPROC pfnOrg[CSUBGIZMOS]={NULL, NULL, NULL, NULL};
+
+
+TCHAR szStatic[]=TEXT("static");
+TCHAR szEdit[]=TEXT("edit");
+TCHAR szCombobox[]=TEXT("combobox");
+TCHAR szListbox[]=TEXT("listbox");
+TCHAR szButton[]=TEXT("button");
+
+
+//Here so PAINT.C can get at it.
+TOOLDISPLAYDATA tdd;
+
+
+
+/*
+ * GizmoPAllocate
+ *
+ * Purpose:
+ * Allocates and initializes a GIZMO data structure.
+ *
+ * Parameters:
+ * pfSuccess LPINT flag indicating success of failure.
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * hWndParent HWND of the parent of this gizmo. Can be NULL for
+ * iType==GIZMOTYPE_BUTTON* or GIZMOTYPE_SEPARATOR.
+ * iType UINT gizmo control type.
+ * iGizmo UINT index of this gizmo in the GizmoBar.
+ * uID UINT identifier to send with WM_COMMAND for this control.
+ * dx, dy UINT width and height of the gizmo.
+ * pszText LPTSTR to the text for edits, listboxes, combobox, and text.
+ * dwStyle DWORD style for edits, lists, and combos, and texts.
+ * hBmp HBITMAP for button gizmos, is applicable.
+ * iImage UINT index into hBmp for the button image, if applicable.
+ * uState UINT initial state of the control.
+ *
+ * Return Value:
+ * LPGIZMO If NULL returned then GizmoPAllocate could not allocate
+ * memory. If a non-NULL pointer is returned with
+ * *pfSuccess, then call GizmoPFree immediately. If you
+ * get a non-NULL pointer and *pfSuccess==TRUE then the
+ * function succeeded.
+ */
+
+LPGIZMO GizmoPAllocate(LPINT pfSuccess, LPLPGIZMO ppFirst, HWND hWndParent
+ , UINT iType, UINT iGizmo, UINT uID, UINT dx, UINT dy, LPTSTR pszText
+ , HBITMAP hBmp, UINT iImage, UINT uState)
+ {
+ LPGIZMO pGizmo;
+ LPGIZMO pCur, pPrev;
+ LPTSTR pszClass;
+ HINSTANCE hInst;
+ UINT i;
+ DWORD dwStyle;
+ HWND hWndE;
+
+ if (NULL==pfSuccess)
+ return NULL;
+
+ //Make sure we know of this gizmo type.
+ if (GIZMOTYPE_MIN > iType || GIZMOTYPE_MAX < iType)
+ return NULL;
+
+ *pfSuccess=FALSE;
+
+ //Allocate the structure
+ pGizmo=(LPGIZMO)LocalAlloc(LPTR, CBGIZMO);
+
+ if (NULL==pGizmo)
+ return NULL;
+
+
+ //Store the necessary information for this gizmo.
+ pGizmo->iType =iType;
+ pGizmo->uID =uID;
+ pGizmo->hBmp =hBmp;
+ pGizmo->iBmp =iImage;
+ pGizmo->uState =uState;
+ pGizmo->fNotify =TRUE;
+
+
+ /*
+ * Insert this structure into our gizmo list. Each time we scan
+ * we increment the index counter (starting at zero) comparing it
+ * to the desired index of insertion. We then know exactly where
+ * to insert this new gizmo. Note that we insert the new gizmo in
+ * the list appropriately for the given owner, so enumerations will
+ * come out ordered in the same way for that owner.
+ */
+
+ i=0;
+ pCur=*ppFirst;
+ pPrev=NULL;
+
+ while (NULL!=pCur && i++ < iGizmo)
+ {
+ pPrev=pCur;
+ pCur =pCur->pNext;
+ }
+
+ //Point to our neighbors
+ pGizmo->pPrev=pPrev;
+ pGizmo->pNext=pCur;
+
+
+ //Point out neighbors to us.
+ if (NULL==pPrev)
+ *ppFirst=pGizmo;
+ else
+ pPrev->pNext=pGizmo;
+
+ if (NULL!=pCur)
+ pCur->pPrev=pGizmo;
+
+
+ //Our x-coordinate is the x of the previous gizmo plus its width.
+ if (NULL!=pPrev)
+ pGizmo->x=pGizmo->pPrev->x+pGizmo->pPrev->dx;
+ else
+ pGizmo->x=4; //First gizmo is at x=4
+
+
+ //If we're a separator or image button, force standards on dx.
+ UIToolConfigureForDisplay(&tdd);
+ pGizmo->cxImage=tdd.cxImage;
+ pGizmo->cyImage=tdd.cyImage;
+
+ if ((GIZMOTYPE_DRAWN & iType) && NULL==hBmp)
+ dx=tdd.cxButton;
+
+ if (GIZMOTYPE_SEPARATOR==iType)
+ dx=6;
+
+ /*
+ * Now create windows for edits, texts, lists, and comboboxes.
+ * First calculate the most often defaults used in the switch.
+ */
+ pGizmo->dx=dx+6;
+ pGizmo->dy=min(dy, tdd.cyButton);
+ pGizmo->y=2;
+ pszClass=NULL;
+
+ //If this is new gizmo is a window, create it.
+ switch (iType)
+ {
+ case GIZMOTYPE_TEXT:
+ pGizmo->dx=dx;
+ pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1; //Center vertically.
+ pszClass=szStatic;
+ dwStyle=SS_LEFT;
+ break;
+
+ case GIZMOTYPE_EDIT:
+ pGizmo->y=(tdd.cyBar-1-pGizmo->dy) >> 1; //Center vertically.
+ pszClass=szEdit;
+ dwStyle=ES_LEFT | WS_BORDER | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_LISTBOX:
+ pGizmo->dy=dy;
+ pszClass=szCombobox;
+ dwStyle=CBS_DROPDOWNLIST | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_COMBOBOX:
+ pGizmo->dy=dy;
+ pszClass=szCombobox;
+ dwStyle=CBS_DROPDOWN | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_BUTTONNORMAL:
+ pGizmo->dy=dy;
+ pszClass=szButton;
+ dwStyle=BS_PUSHBUTTON | WS_TABSTOP;
+ break;
+
+ case GIZMOTYPE_SEPARATOR:
+ pGizmo->dx=dx;
+ pGizmo->y=3;
+ break;
+
+ case GIZMOTYPE_BUTTONATTRIBUTEIN:
+ case GIZMOTYPE_BUTTONATTRIBUTEEX:
+ case GIZMOTYPE_BUTTONCOMMAND:
+ pGizmo->dx=dx;
+ pGizmo->y=3;
+ break;
+ }
+
+
+ //If we matched a classname, create a window.
+ if (GIZMOTYPE_WINDOWS & iType)
+ {
+ if (!IsWindow(hWndParent))
+ return pGizmo;
+
+ hInst=(HINSTANCE) GetWindowLong(hWndParent, GWL_HINSTANCE);
+
+ pGizmo->hWnd=CreateWindow(pszClass, pszText
+ , dwStyle | WS_CHILD | WS_VISIBLE, pGizmo->x, pGizmo->y
+ , dx, pGizmo->dy, hWndParent, (HMENU)uID, hInst, NULL);
+
+ if (NULL==pGizmo->hWnd)
+ return pGizmo;
+
+ /*
+ * Subclass comboboxes, listboxes, edits, and windowed buttons.
+ * We use iType to index the original proc array so we can use
+ * a single subclass procedure for all controls. If you mess
+ * with the gizmo type definitions, this is going to break.
+ */
+
+ if (GIZMOTYPE_WINDOWS & iType && GIZMOTYPE_TEXT!=iType)
+ {
+ //Give the window its type.
+ BITPOSITION(iType, i);
+ SetProp(pGizmo->hWnd, SZTYPEPROP, (HANDLE)i);
+
+ if (NULL==pfnOrg[i])
+ pfnOrg[i]=(WNDPROC)GetWindowLong(pGizmo->hWnd, GWL_WNDPROC);
+
+ SetWindowLong(pGizmo->hWnd, GWL_WNDPROC, (LONG)GenericSubProc);
+
+ //If we're a combobox, get the edit control and subclass it.
+ if (GIZMOTYPE_COMBOBOX==iType)
+ {
+ hWndE=GetDlgItem(pGizmo->hWnd, ID_COMBOEDIT);
+ SetProp(hWndE, SZTYPEPROP, (HANDLE)-1); //Special flag.
+
+ if (NULL==pfnOrg[0])
+ pfnOrg[0]=(WNDPROC)GetWindowLong(pGizmo->hWnd, GWL_WNDPROC);
+
+ SetWindowLong(hWndE, GWL_WNDPROC, (LONG)GenericSubProc);
+ }
+ }
+ }
+
+
+ //Finally, move all our neighbors to the right over to accomodate us.
+ GizmosExpand(pGizmo);
+
+ *pfSuccess=TRUE;
+ return pGizmo;
+ }
+
+
+
+
+
+
+/*
+ * GizmoPFree
+ *
+ * Purpose:
+ * Reverses all initialization done by GizmoPAllocate, cleaning up
+ * any allocations including the application structure itself.
+ *
+ * Parameters:
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * pGizmo LPGIZMO to the structure
+ *
+ * Return Value:
+ * LPGIZMO NULL if successful, pGizmo if not, meaning we couldn't
+ * free something.
+ */
+
+LPGIZMO GizmoPFree(LPLPGIZMO ppFirst, LPGIZMO pGizmo)
+ {
+ int i;
+
+ if (NULL==pGizmo)
+ return NULL;
+
+ //Move other gizmos to fill in this gap.
+ GizmosCompact(pGizmo);
+
+ //Unsubclass
+ if (GIZMOTYPE_WINDOWS & pGizmo->iType && GIZMOTYPE_TEXT!=pGizmo->iType)
+ {
+ i=(int)GetProp(pGizmo->hWnd, SZTYPEPROP);
+ RemoveProp(pGizmo->hWnd, SZTYPEPROP);
+
+ SetWindowLong(pGizmo->hWnd, GWL_WNDPROC, (LONG)pfnOrg[i]);
+ }
+
+ //If this was a window gizmo, destroy the window.
+ if (NULL!=pGizmo->hWnd && IsWindow(pGizmo->hWnd))
+ DestroyWindow(pGizmo->hWnd);
+
+ //Unlink ourselves.
+ if (NULL!=pGizmo->pNext)
+ pGizmo->pNext->pPrev=pGizmo->pPrev;
+
+ if (NULL!=pGizmo->pPrev)
+ pGizmo->pPrev->pNext=pGizmo->pNext;
+ else
+ *ppFirst=pGizmo->pNext;
+
+ return (LPGIZMO)LocalFree((HLOCAL)(UINT)(LONG)pGizmo);
+ }
+
+
+
+
+
+
+/*
+ * GizmosExpand
+ *
+ * Purpose:
+ * Given a starting gizmo and a width, moves it and all gizmos to its
+ * right to the right by the width to make space for showing or creating
+ * a new gizmo.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO specifying the gizmo that was inserted.
+ *
+ * Return Value:
+ * None
+ */
+
+void GizmosExpand(LPGIZMO pGizmo)
+ {
+ int cx;
+
+ cx=(int)pGizmo->dx;
+
+ /*
+ * If we and the next control are buttons, use our width-1 to
+ * expand so we overlap borders with our neighboring button.
+ */
+
+ if (NULL!=pGizmo->pNext)
+ {
+ if ((GIZMOTYPE_BUTTONS & pGizmo->pNext->iType)
+ && (GIZMOTYPE_BUTTONS & pGizmo->iType))
+ cx-=1;
+ }
+
+ //Walk the gizmo list moving them right by our width.
+ pGizmo=pGizmo->pNext;
+
+ while (NULL!=pGizmo)
+ {
+ pGizmo->x+=cx;
+
+ //hWnd is NULL for buttons and separators.
+ if (NULL!=pGizmo->hWnd)
+ SetWindowPos(pGizmo->hWnd, NULL, pGizmo->x, pGizmo->y, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+
+ pGizmo=pGizmo->pNext;
+ }
+
+ return;
+ }
+
+
+
+
+
+
+
+/*
+ * GizmosCompact
+ *
+ * Purpose:
+ * Given a gizmo, moves all other gizmos to the right of it to the
+ * left by its width on the GizmoBar. Used when removing or hiding
+ * the gizmo.
+ *
+ * Parameters:
+ * pGizmo LPGIZMO that is going away, visibly or physically.
+ *
+ * Return Value:
+ * None
+ */
+
+void GizmosCompact(LPGIZMO pGizmo)
+ {
+ UINT cx;
+ LPGIZMO pCur;
+
+ //Move all the gizmos beyond us on the GizmoBar back by our width.
+ if (NULL!=pGizmo->pNext)
+ {
+ cx=pGizmo->pNext->x - pGizmo->x;
+ pCur=pGizmo->pNext;
+
+ while (NULL!=pCur)
+ {
+ pCur->x-=cx;
+
+ if (NULL!=pCur->hWnd)
+ {
+ SetWindowPos(pCur->hWnd, NULL, pCur->x, pCur->y
+ , 0, 0, SWP_NOZORDER | SWP_NOSIZE);
+ }
+
+ pCur=pCur->pNext;
+ }
+ }
+
+ return;
+ }
+
+
+
+
+
+
+/*
+ * GizmoPFind
+ *
+ * Purpose:
+ * Given a GIZMO identifier, locates and returns a pointer to the structure
+ * for that position.
+ *
+ * Parameters:
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * uID UINT identifier to find.
+ *
+ * Return Value:
+ * LPGIZMO A pointer to a GIZMO structure allocated through
+ * GizmoPAllocate, NULL if iGizmo is out of range.
+ */
+
+LPGIZMO GizmoPFind(LPLPGIZMO ppFirst, UINT uID)
+ {
+ LPGIZMO pGizmo;
+
+ pGizmo=*ppFirst;
+
+ /*
+ * Yep, linear search, but a better search algorithm won't improve
+ * things appreciably. The better thing to optimize is what the
+ * caller passes as ppFirst.
+ */
+ while (NULL!=pGizmo && uID!=pGizmo->uID)
+ pGizmo=pGizmo->pNext;
+
+ return pGizmo;
+ }
+
+
+
+
+
+
+/*
+ * GizmoFEnum
+ *
+ * Purpose:
+ * Enumerates the list of GIZMO structures, passing each one to
+ * an application-defined callback.
+ *
+ * Parameters:
+ * ppFirst LPLPGIZMO providing the first gizmo in this list.
+ * pfnEnum LPFNGIZMOENUM to call for each enumerated structure.
+ * dw DWORD extra data to pass to the enumeration function.
+ *
+ * Return Value:
+ * LPGIZMO NULL if the enumeration completed. Otherwise a pointer
+ * to the gizmo that enumeration stopped on.
+ */
+
+LPGIZMO GizmoPEnum(LPLPGIZMO ppFirst, LPFNGIZMOENUM pfnEnum, DWORD dw)
+ {
+ LPGIZMO pGizmo;
+ UINT i=0;
+
+ pGizmo=*ppFirst;
+
+ while (NULL!=pGizmo)
+ {
+ if (!(*pfnEnum)(pGizmo, i++, dw))
+ break;
+
+ pGizmo=pGizmo->pNext;
+ }
+
+ return pGizmo;
+ }
+
+
+
+
+/*
+ * GizmoPStateSet
+ *
+ * Purpose:
+ * State maniuplation functions. Set and Clear also invalidate
+ * this gizmo's rectangle on the given window and forces a repaint.
+ *
+ * Parameters:
+ * hWnd HWND of the window to repaint.
+ * pGizmo LPGIZMO affected.
+ * dwNew DWORD new state flags.
+ *
+ * Return Value:
+ * UINT Previous state.
+ */
+
+UINT GizmoPStateSet(HWND hWnd, LPGIZMO pGizmo, UINT uNew)
+ {
+ UINT uRet;
+ RECT rc;
+
+ if (GIZMOTYPE_SEPARATOR==pGizmo->iType)
+ return pGizmo->uState;
+
+ //Preserve the color conversion flags across this state change.
+ uRet=pGizmo->uState;
+ pGizmo->uState=(uNew & 0x00FF) | (uRet & 0xFF00);
+
+ //Adjust the rectangle by one to avoid repainting borders.
+ SetRect(&rc, pGizmo->x+1, pGizmo->y+1, pGizmo->x+pGizmo->dx-1, pGizmo->y+pGizmo->dy-1);
+ InvalidateRect(hWnd, &rc, FALSE);
+ UpdateWindow(hWnd);
+
+ return uRet;
+ }
+
+
+
+
+
+
+
+
+/*
+ * GizmoPCheck
+ *
+ * Purpose:
+ * Handles checking a single button in a group of attribute buttons.
+ * If the gizmo belongs to a group of mutually exclusive buttons then
+ * the others surrounding it are unchecked appropriately.
+ *
+ * Parameters:
+ * hWnd HWND of the GizmoBar.
+ * pGizmo LPGIZMO of the gizmo affected.
+ * fCheck BOOL TRUE to check the button, FALSE to uncheck.
+ *
+ * Return Value:
+ * BOOL TRUE if the gizmo was previously checked, FALSE
+ * otherwise.
+ */
+
+BOOL GizmoPCheck(HWND hWnd, LPGIZMO pGizmo, BOOL fCheck)
+ {
+ BOOL fPrevCheck;
+ LPGIZMO pCur;
+
+
+ //Ignore command buttons.
+ if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType)
+ return FALSE;
+
+ //Get the previous state
+ fPrevCheck=(BOOL)(BUTTONGROUP_DOWN & pGizmo->uState);
+
+
+ //Simply set the state for inclusive attribute buttons.
+ if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType)
+ {
+ if (pGizmo->fDisabled)
+ {
+ GizmoPStateSet(hWnd, pGizmo
+ , fCheck ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DISABLED);
+ }
+ else
+ {
+ GizmoPStateSet(hWnd, pGizmo
+ , fCheck ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_UP);
+ }
+ }
+
+
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType)
+ {
+ //We cannot uncheck an exclusive attribute
+ if (!fCheck)
+ return fPrevCheck;
+
+ /*
+ * For exclusive buttons we have to do more work. First, if we're
+ * already checked (incliding DOWN and MOUSEDOWN) then we set DOWN
+ * and exit. If we're not already checked, then we look for the
+ * gizmo around us, backwards and forwards, that is checked and
+ * uncheck him.
+ */
+
+ //Search backwards.
+ pCur=pGizmo->pPrev;
+
+ while (NULL!=pCur)
+ {
+ //Stop at any non-exclusive attribute.
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)
+ {
+ pCur=NULL;
+ break;
+ }
+
+ //If it's down, set it up and we've finished.
+ if (BUTTONGROUP_DOWN & pCur->uState)
+ break;
+
+ pCur=pCur->pPrev;
+ }
+
+
+ //If we didn't find a previous one, pCur is NULL, so look ahead.
+ if (NULL==pCur)
+ {
+ pCur=pGizmo->pNext;
+
+ while (NULL!=pCur)
+ {
+ //Stop at any non-exclusive attribute.
+ if (GIZMOTYPE_BUTTONATTRIBUTEEX!=pCur->iType)
+ {
+ pCur=NULL;
+ break;
+ }
+
+ //If it's down, set it up and we've finished.
+ if (BUTTONGROUP_DOWN & pCur->uState)
+ break;
+
+ pCur=pCur->pNext;
+ }
+ }
+
+ //If pCur is non-NULL, the we found a neighbor, so uncheck him
+ if (NULL!=pCur)
+ {
+ GizmoPStateSet(hWnd, pCur
+ , (pGizmo->fDisabled) ? ATTRIBUTEBUTTON_DISABLED : ATTRIBUTEBUTTON_UP);
+ }
+
+ //Always set ourselves down
+ GizmoPStateSet(hWnd, pGizmo
+ , (pGizmo->fDisabled) ? ATTRIBUTEBUTTON_DOWNDISABLED : ATTRIBUTEBUTTON_DOWN);
+ }
+
+ return fPrevCheck;
+ }
+
+
+
+
+
+
+
+/*
+ * GenericSubProc
+ *
+ * Purpose:
+ * Subclasses window controls in Gizmos so we can trap the tab key and
+ * tab to the next control. We can have one shared generic subclass
+ * procedure because we save the type index for this control in the
+ * property "iType." This allows us to look up the original procedure
+ * in the pfnOrg array.
+ *
+ * Parameters:
+ * Standard
+ *
+ * Return Value:
+ * Standard
+ */
+
+//LRESULT FAR PASCAL EXPORT GenericSubProc(HWND hWnd, UINT iMsg
+LRESULT FAR PASCAL GenericSubProc(HWND hWnd, UINT iMsg
+ , WPARAM wParam, LPARAM lParam)
+ {
+ LONG lRet;
+ RECT rc;
+ RECT rcE;
+ HWND hWndE;
+ HBRUSH hBr;
+ HDC hDC;
+ UINT dx;
+ UINT iType, i;
+
+ i=(int)GetProp(hWnd, SZTYPEPROP);
+ iType=POSITIONBIT(i);
+
+ //Special: paint the gap in drop-down comboboxes.
+ if (GIZMOTYPE_COMBOBOX==iType && WM_PAINT==iMsg)
+ {
+ //Do default painting.
+ lRet=(*pfnOrg[i])(hWnd, iMsg, wParam, lParam);
+
+ hWndE=GetDlgItem(hWnd, ID_COMBOEDIT);
+
+ GetClientRect(hWnd, &rc);
+ GetClientRect(hWndE, &rcE);
+
+ //The width of the button is the scroll bar width.
+ dx=GetSystemMetrics(SM_CXVSCROLL);
+
+ //Calculate the rectangle
+ rc.right -=dx;
+ rc.left =rcE.right;
+ rc.bottom+=1;
+
+ //Paint the gap
+ hDC=GetDC(hWnd); //Already did BeginPaint and EndPaint
+
+ hBr=CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+ FillRect(hDC, &rc, hBr);
+ DeleteObject(hBr);
+
+ ReleaseDC(hWnd, hDC);
+ return lRet;
+ }
+
+ //Control tabbing to the next or previous control in the GizmoBar.
+ if (WM_KEYDOWN==iMsg && VK_TAB==wParam)
+ {
+ hWndE=hWnd;
+
+ if (-1==i)
+ hWndE=GetParent(hWnd);
+
+ hWndE=GetNextDlgTabItem(GetParent(hWndE), hWnd, (BOOL)(GetKeyState(VK_SHIFT)));
+ SetFocus(hWndE);
+ return 0L;
+ }
+
+ if (-1==i) i=0;
+
+ //Eat tab chars in edit controls to prevent beeping.
+ if (0==i && WM_CHAR==iMsg && VK_TAB==wParam)
+ return 0L;
+
+
+ //Do this or edit controls bomb big-time.
+ return CallWindowProc(pfnOrg[i], hWnd, iMsg, wParam, lParam);
+ }