diff options
Diffstat (limited to 'private/oleutest/letest/gizmobar/gizmo.c')
-rw-r--r-- | private/oleutest/letest/gizmobar/gizmo.c | 766 |
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); + } |