767 lines
19 KiB
C
767 lines
19 KiB
C
|
/*
|
||
|
* 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) GetWindowLongPtr(hWndParent, GWLP_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)GetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC);
|
||
|
|
||
|
SetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC, (LONG_PTR)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)GetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC);
|
||
|
|
||
|
SetWindowLongPtr(hWndE, GWLP_WNDPROC, (LONG_PTR)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);
|
||
|
|
||
|
SetWindowLongPtr(pGizmo->hWnd, GWLP_WNDPROC, (LONG_PTR)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)
|
||
|
{
|
||
|
LRESULT 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);
|
||
|
}
|