468 lines
13 KiB
C
468 lines
13 KiB
C
/*
|
|
* 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 <windows.h>
|
|
#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;
|
|
}
|