/* * GIZMOBAR.C * GizmoBar Version 1.00, Win32 version August 1993 * * Contains the main window procedure of the GizmoBar control * that handles mouse logic and Windows messages. * * 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 #include "gizmoint.h" /* * GizmoBarWndProc * * Purpose: * Window Procedure for the GizmoBar custom control. Handles all * messages like WM_PAINT just as a normal application window would. * Any message not processed here should go to DefWindowProc. * * Parameters: * Standard * * Return Value: * Standard */ LRESULT FAR PASCAL GizmoBarWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { BOOL fSuccess; BOOL fTemp; LPCREATESTRUCT pCreate; LPGIZMOBAR pGB; LPGIZMO pGizmo; RECT rc; POINT pt; short x, y; COLORREF cr; COMMANDPARAMS(wID, wCode, hWndMsg); pGB=(LPGIZMOBAR)GetWindowLong(hWnd, GBWL_STRUCTURE); //Pass control messages onto another function for processing. if (iMsg >= WM_USER) return GBMessageHandler(hWnd, iMsg, wParam, lParam, pGB); switch (iMsg) { case WM_NCCREATE: pCreate=(LPCREATESTRUCT)lParam; pGB=GizmoBarPAllocate((LPINT)&fSuccess, hWnd, pCreate->hInstance , pCreate->hwndParent, pCreate->style, 0 , (UINT)pCreate->hMenu); if (!fSuccess) { GizmoBarPFree(pGB); return -1L; } else SetWindowLong(hWnd, GBWL_STRUCTURE, (LONG)pGB); return DefWindowProc(hWnd, iMsg, wParam, lParam); case WM_DESTROY: /* * We want to clean up before DestroyWindow nukes all the * children, so WM_DESTROY is a better to do it than * WM_NCDESTROY. */ GizmoBarPFree(pGB); break; case WM_ERASEBKGND: /* * Eat this message to avoid erasing portions that * we are going to repaint in WM_PAINT. Part of a * change-state-and-repaint strategy is to rely on * WM_PAINT to do anything visual, which includes * erasing invalid portions. Letting WM_ERASEBKGND * erase the background is redundant. */ return TRUE; #ifdef WIN32 case WM_CTLCOLORBTN: case WM_CTLCOLORSTATIC: fTemp=TRUE; #else case WM_CTLCOLOR: //Change the color of static text on the GizmoBar. fTemp=(HIWORD(lParam)==CTLCOLOR_STATIC || HIWORD(lParam)==CTLCOLOR_BTN); #endif if (fTemp) { cr=GetSysColor(COLOR_BTNFACE); SetTextColor((HDC)wParam, GetSysColor(COLOR_BTNTEXT)); SetBkColor((HDC)wParam, cr); /* * If the system colors have changed, then crFace will * not be equal to COLOR_BTNFACE, so we reinitialize the * background brush. This scheme handles system color * changes appropriately without processing WM_WININICHANGE * and without blindly creating a new brush on every * WM_CTLCOLOR message. */ if (cr!=pGB->crFace) { pGB->crFace=cr; if (NULL!=pGB->hBrFace) DeleteObject(pGB->hBrFace); pGB->hBrFace=CreateSolidBrush(pGB->crFace); } return (LONG)(UINT)pGB->hBrFace; } return DefWindowProc(hWnd, iMsg, wParam, lParam); case WM_PAINT: GizmoBarPaint(hWnd, pGB); break; case WM_SETFONT: /* * wParam has the new font that we now send to all other * windows controls in us. We control repaints here to * prevent a lot of repainting for each control. */ DefWindowProc(hWnd, WM_SETREDRAW, FALSE, 0L); if ((WPARAM)NULL!=wParam) { pGB->hFont=(HFONT)wParam; GizmoPEnum(&pGB->pGizmos, FEnumChangeFont, (DWORD)(LPSTR)pGB); DefWindowProc(hWnd, WM_SETREDRAW, TRUE, 0L); InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); } break; case WM_GETFONT: return (LRESULT)(UINT)pGB->hFont; case WM_ENABLE: /* * wParam has the new enable flag that we use to enable * or disable ALL controls in us at one time. We also turn * the redraw off to prevent a lot of flicker. */ DefWindowProc(hWnd, WM_SETREDRAW, FALSE, 0L); pGB->fEnabled=(BOOL)wParam; GizmoPEnum(&pGB->pGizmos, FEnumEnable, (DWORD)(LPSTR)pGB); DefWindowProc(hWnd, WM_SETREDRAW, TRUE, 0L); InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); break; case WM_CANCELMODE: pGizmo=pGB->pGizmoTrack; pGB->fTracking=FALSE; pGB->fMouseOut=FALSE; if (NULL!=pGizmo) GizmoPStateSet(hWnd, pGizmo, COMMANDBUTTON_UP); ReleaseCapture(); break; case WM_LBUTTONDBLCLK: case WM_LBUTTONDOWN: //Get the mouse coordinates. x=LOWORD(lParam); y=HIWORD(lParam); /* * See if we hit a command or attribute gizmo or not. Anything * else that is a control will get the message instead of * us anyway, so we don't have to check. FEnumHitTest also * validates drawn gizmos, enabled, and visible, so we don't. */ pGizmo=GizmoPEnum(&pGB->pGizmos, FEnumHitTest, lParam); if (NULL==pGizmo) break; //Didn't hit one matching our needs. /* * Inform the associate that a command was hit like a menu item. */ if (NULL!=pGB->hWndAssociate) { if (pGizmo->fNotify) SendMenuSelect(pGB->hWndAssociate, pGizmo->uID, 0, 0); } /* * We hit a button. If it's a command or attribute, then change * the state and start tracking. */ pGB->fTracking=TRUE; pGB->pGizmoTrack=pGizmo; pGB->fMouseOut=FALSE; SetCapture(hWnd); pGizmo->uStateOrg=pGizmo->uState; GizmoPStateSet(hWnd, pGizmo, ATTRIBUTEBUTTON_MOUSEDOWN); break; case WM_MOUSEMOVE: POINTFROMLPARAM(pt, lParam); if (!pGB->fTracking) break; pGizmo=pGB->pGizmoTrack; SetRect(&rc, pGizmo->x, pGizmo->y, pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy); fTemp=pGB->fMouseOut; pGB->fMouseOut=!PtInRect(&rc, pt); //If the mouse went out, change state to the original. if (!fTemp && pGB->fMouseOut) { GizmoPStateSet(hWnd, pGizmo, pGizmo->uStateOrg); if (NULL!=pGB->hWndAssociate) { //Notify that we left the button if (pGizmo->fNotify) SendMenuSelect(pGB->hWndAssociate, 0x0000, 0xFFFF, 0); } } if (fTemp && !pGB->fMouseOut) { GizmoPStateSet(hWnd, pGizmo, ATTRIBUTEBUTTON_MOUSEDOWN); if (NULL!=pGB->hWndAssociate) { //Notify that we pressed down again if (pGizmo->fNotify) SendMenuSelect(pGB->hWndAssociate, pGizmo->uID, 0x0000, 0); } } break; case WM_LBUTTONUP: if (!pGB->fTracking) break; pGB->fTracking=FALSE; pGizmo=pGB->pGizmoTrack; ReleaseCapture(); /* * Repaint if we were actually below the mouse when this * occurred. For command buttons, pop the button up. For * attributes, either toggle the state (inclusive buttons) * or check the selected one (exclusive buttons). */ if (!pGB->fMouseOut) { //Command buttons always come up. if (GIZMOTYPE_BUTTONCOMMAND==pGizmo->iType) GizmoPStateSet(hWnd, pGizmo, COMMANDBUTTON_UP); //Attribute inclusive buttons toggle if (GIZMOTYPE_BUTTONATTRIBUTEIN==pGizmo->iType) GizmoPCheck(hWnd, pGizmo, !(BUTTONGROUP_DOWN & pGizmo->uStateOrg)); //Attribure exclusive buttons are always checked. if (GIZMOTYPE_BUTTONATTRIBUTEEX==pGizmo->iType) GizmoPCheck(hWnd, pGizmo, TRUE); //Only send messages if notify is ON. if (NULL!=pGB->hWndAssociate && pGizmo->fNotify) { SendMenuSelect(pGB->hWndAssociate, 0, 0xFFFF, 0); SendCommand(pGB->hWndAssociate, pGizmo->uID, BN_CLICKED, hWnd); } } break; case WM_COMMAND: //Pass control messages on if the gizmo's notify is ON. if (NULL!=pGB->hWndAssociate) { pGizmo=PGizmoFromHwndID(hWnd, wID); if (NULL!=pGizmo) { if (pGizmo->fNotify) SendMessage(pGB->hWndAssociate, iMsg, wParam, lParam); } } break; default: return DefWindowProc(hWnd, iMsg, wParam, lParam); } return 0L; } /* * FEnumChangeFont * * Purpose: * Enumeration callback for all the gizmos we know about in order to * send a new font to them that's stored in LPGIZMOBAR in dw. * * Parameters: * pGizmo LPGIZMO to draw. * iGizmo UINT index on the GizmoBar of this gizmo. * dw DWORD extra data passed to GizmoPEnum, in our case * the GizmoBar's pGB. * * Return Value: * BOOL TRUE to continue the enumeration, FALSE otherwise. */ BOOL FAR PASCAL FEnumChangeFont(LPGIZMO pGizmo, UINT iGizmo, DWORD dw) { LPGIZMOBAR pGB=(LPGIZMOBAR)dw; //We only need to change fonts in windowed controls using WM_SETFONT if (NULL!=pGizmo->hWnd) SendMessage(pGizmo->hWnd, WM_SETFONT, (WPARAM)pGB->hFont, 1L); return TRUE; } /* * FEnumEnable * * Purpose: * Enumeration callback for all the gizmos we know about in order to * enable or disable them from the WM_ENABLE message. * * Parameters: * pGizmo LPGIZMO to draw. * iGizmo UINT index on the GizmoBar of this gizmo. * dw DWORD extra data passed to GizmoPEnum, in our case * the GizmoBar's pGB. * * Return Value: * BOOL TRUE to continue the enumeration, FALSE otherwise. */ BOOL FAR PASCAL FEnumEnable(LPGIZMO pGizmo, UINT iGizmo, DWORD dw) { LPGIZMOBAR pGB=(LPGIZMOBAR)dw; BOOL fEnable=pGB->fEnabled; //NOTE: This code is duplicated in GBGizmoEnable in API.C if (NULL!=pGizmo->hWnd) EnableWindow(pGizmo->hWnd, fEnable); else { //If we're not down, command and attribute buttons act the same. if (!(BUTTONGROUP_DOWN & pGizmo->uState)) { GizmoPStateSet(pGB->hWnd, pGizmo , fEnable ? COMMANDBUTTON_UP : COMMANDBUTTON_DISABLED); } else { //Attribute buttons are a little more sensitive with DOWNDISABLED GizmoPStateSet(pGB->hWnd, pGizmo , fEnable ? ATTRIBUTEBUTTON_DOWN : ATTRIBUTEBUTTON_DOWNDISABLED); } } return TRUE; } /* * FEnumHitTest * * Purpose: * Enumeration callback for all the gizmos we know about in order to * hit-test them. * * Parameters: * pGizmo LPGIZMO to draw. * iGizmo UINT index on the GizmoBar of this gizmo. * dw DWORD extra data passed to GizmoPEnum, in our case * the hDC on which to draw. * * Return Value: * BOOL TRUE to continue the enumeration, FALSE otherwise. */ BOOL FAR PASCAL FEnumHitTest(LPGIZMO pGizmo, UINT iGizmo, DWORD dw) { RECT rc; POINT pt; POINTFROMLPARAM(pt, dw); //Hit tests have to happen on visible, enabled, and drawn controls only. if (GIZMOTYPE_DRAWN & pGizmo->iType && !pGizmo->fHidden && !(BUTTONGROUP_DISABLED & pGizmo->uState)) { SetRect(&rc, pGizmo->x, pGizmo->y , pGizmo->x+pGizmo->dx, pGizmo->y+pGizmo->dy); //Stop enumeration if we have a hit. return !PtInRect(&rc, pt); } return TRUE; }