|
|
/******************************Module*Header*******************************\
* Module Name: buttons.c * * Bitmap button support. On Daytona bitmap buttons are provided by * mmcntrls. On Chicago there is no mmcntrls, so we use the functions * in this file. * * * Created: 19-04-94 * Author: Stephen Estrop [StephenE] * * Copyright (c) 1993 Microsoft Corporation \**************************************************************************/ #pragma warning( once : 4201 4214 )
#define NOOLE
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "buttons.h"
#include "literals.h"
/* -------------------------------------------------------------------------
** Color globals ** ------------------------------------------------------------------------- */ int nSysColorChanges = 0; DWORD rgbFace; DWORD rgbShadow; DWORD rgbHilight; DWORD rgbFrame;
/*****************************Private*Routine******************************\
* PatB * * Fast way to fill an rectangle with a solid colour. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void PatB( HDC hdc, int x, int y, int dx, int dy, DWORD rgb ) { RECT rc;
SetBkColor(hdc,rgb); rc.left = x; rc.top = y; rc.right = x + dx; rc.bottom = y + dy;
ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL); }
/*****************************Private*Routine******************************\
* CheckSysColors * * Checks the system colors and updates the cached global variables if * they have changed. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void CheckSysColors( void ) { static COLORREF rgbSaveFace = 0xffffffffL, rgbSaveShadow = 0xffffffffL, rgbSaveHilight = 0xffffffffL, rgbSaveFrame = 0xffffffffL;
rgbFace = GetSysColor(COLOR_BTNFACE); rgbShadow = GetSysColor(COLOR_BTNSHADOW); rgbHilight = GetSysColor(COLOR_BTNHIGHLIGHT); rgbFrame = GetSysColor(COLOR_WINDOWFRAME);
if (rgbSaveFace!=rgbFace || rgbSaveShadow!=rgbShadow || rgbSaveHilight!=rgbHilight || rgbSaveFrame!=rgbFrame) { ++nSysColorChanges;
rgbSaveFace = rgbFace; rgbSaveShadow = rgbShadow; rgbSaveHilight = rgbHilight; rgbSaveFrame = rgbFrame;
} }
/* -------------------------------------------------------------------------
** Button globals -- some of these should be constants ** ------------------------------------------------------------------------- */ const TCHAR szBbmProp[] = TEXT("ButtonBitmapProp"); const TCHAR szButtonProp[] = TEXT("ButtonProp");
typedef struct tagBTNSTATE { /* instance data for toolbar window */ WNDPROC lpfnDefProc; HWND hwndToolTips; HINSTANCE hInst; UINT wID; UINT uStyle; HBITMAP hbm; HDC hdcGlyphs; HDC hdcMono; HBITMAP hbmMono; HBITMAP hbmDefault; int dxBitmap; int dyBitmap; int nButtons; int nSysColorChanges; BITMAPBTN Buttons[1]; } BTNSTATE, NEAR *PBTNSTATE, FAR *LPBTNSTATE;
typedef struct { WNDPROC lpfnDefProc; HWND hwndParent; HWND hwndToolTips; } BTN_INFO, *LPBTN_INFO;
LRESULT CALLBACK ButtonSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
LRESULT CALLBACK ParentSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
void FAR PASCAL RelayToToolTips( HWND hwndToolTips, HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam );
BOOL InitObjects( LPBTNSTATE pTBState );
BOOL FreeObjects( LPBTNSTATE pTBState );
void CreateButtonMask( LPBTNSTATE pTBState, PBITMAPBTN pTBButton );
/*****************************Private*Routine******************************\
* InitObjects * * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL InitObjects( LPBTNSTATE pTBState ) { pTBState->hdcGlyphs = CreateCompatibleDC(NULL); if (pTBState->hdcGlyphs == NULL ) { return FALSE; }
pTBState->hdcMono = CreateCompatibleDC(NULL); if (pTBState->hdcMono == NULL ) { DeleteObject( pTBState->hdcGlyphs ); return FALSE; }
pTBState->hbmMono = CreateBitmap( pTBState->dxBitmap, pTBState->dyBitmap, 1, 1, NULL); if ( pTBState->hbmMono == NULL ) { DeleteObject( pTBState->hdcGlyphs ); DeleteObject( pTBState->hdcMono ); return FALSE; }
pTBState->hbmDefault = SelectObject(pTBState->hdcMono, pTBState->hbmMono);
return TRUE; }
/*****************************Private*Routine******************************\
* FreeObjects * * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL FreeObjects( LPBTNSTATE pTBState ) { if (pTBState->hdcMono) { SelectObject(pTBState->hdcMono, pTBState->hbmDefault); DeleteDC(pTBState->hdcMono); /* toast the DCs */ }
if (pTBState->hdcGlyphs) { DeleteDC(pTBState->hdcGlyphs); }
if (pTBState->hbmMono) { DeleteObject(pTBState->hbmMono); }
return TRUE; }
/*****************************Private*Routine******************************\
* CreateButtonMask * * create a mono bitmap mask: * 1's where color == COLOR_BTNFACE || COLOR_HILIGHT * 0's everywhere else * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void CreateButtonMask( LPBTNSTATE pTBState, PBITMAPBTN pTBButton ) { /* initalize whole area with 0's */ PatBlt( pTBState->hdcMono, 0, 0, pTBState->dxBitmap, pTBState->dyBitmap, WHITENESS);
/* create mask based on color bitmap
** convert this to 1's */ SetBkColor(pTBState->hdcGlyphs, rgbFace); BitBlt( pTBState->hdcMono, 0, 0, pTBState->dxBitmap, pTBState->dyBitmap, pTBState->hdcGlyphs, pTBButton->iBitmap * pTBState->dxBitmap, 0, SRCCOPY );
/* convert this to 1's */ SetBkColor(pTBState->hdcGlyphs, rgbHilight);
/* OR in the new 1's */ BitBlt( pTBState->hdcMono, 0, 0, pTBState->dxBitmap, pTBState->dyBitmap, pTBState->hdcGlyphs, pTBButton->iBitmap * pTBState->dxBitmap, 0, SRCPAINT ); }
#define PSDPxax 0x00B8074A
/*****************************Private*Routine******************************\
* BtnDrawButton * * * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void WINAPI BtnDrawButton( HWND hwnd, HDC hdc, int dx, int dy, LPBITMAPBTN ptButton ) { int glyph_offset; HBRUSH hbrOld, hbr; BOOL bMaskCreated = FALSE; RECT rcFocus; PBTNSTATE pTBState; int x = 0, y = 0;
pTBState = (PBTNSTATE)GetProp(hwnd, szBbmProp);
CheckSysColors(); if (pTBState->nSysColorChanges != nSysColorChanges) {
DeleteObject( pTBState->hbm ); pTBState->hbm = CreateMappedBitmap( pTBState->hInst, pTBState->wID, TRUE, NULL, 0); pTBState->nSysColorChanges = nSysColorChanges; }
/*
** erase with face color */
PatB(hdc, x, y, dx, dy, rgbFace); SetRect( &rcFocus, x, y, x + dx, y + dy );
if (ptButton->fsState & BTNSTATE_PRESSED) { DrawEdge( hdc, &rcFocus, EDGE_SUNKEN, BF_RECT ); glyph_offset = 1; } else { DrawEdge( hdc, &rcFocus, EDGE_RAISED, BF_RECT ); glyph_offset = 0; }
/*
** make the coordinates the interior of the button */ x += 2; y += 2; dx -= 4; dy -= 4;
SelectObject( pTBState->hdcGlyphs, pTBState->hbm );
/* now put on the face */
/*
** We need to centre the Bitmap here within the button */ x += (dx - pTBState->dxBitmap ) / 2; y += (dy - pTBState->dyBitmap ) / 2;
if (!(ptButton->fsState & BTNSTATE_DISABLED)) {
/* regular version */ BitBlt( hdc, x + glyph_offset, y + glyph_offset, pTBState->dxBitmap, pTBState->dyBitmap, pTBState->hdcGlyphs, ptButton->iBitmap * pTBState->dxBitmap, 0, SRCCOPY); } else {
/* disabled version */ bMaskCreated = TRUE; CreateButtonMask(pTBState, ptButton );
SetTextColor(hdc, 0L); /* 0's in mono -> 0 (for ROP) */ SetBkColor(hdc, 0x00FFFFFF); /* 1's in mono -> 1 */
hbr = CreateSolidBrush(rgbHilight); if (hbr) { hbrOld = SelectObject(hdc, hbr); if (hbrOld) { /* draw hilight color where we have 0's in the mask */ BitBlt( hdc, x + 1, y + 1, pTBState->dxBitmap, pTBState->dyBitmap, pTBState->hdcMono, 0, 0, PSDPxax); SelectObject(hdc, hbrOld); } DeleteObject(hbr); }
hbr = CreateSolidBrush(rgbShadow); if (hbr) { hbrOld = SelectObject(hdc, hbr); if (hbrOld) { /* draw the shadow color where we have 0's in the mask */ BitBlt(hdc, x, y, pTBState->dxBitmap, pTBState->dyBitmap, pTBState->hdcMono, 0, 0, PSDPxax); SelectObject(hdc, hbrOld); } DeleteObject(hbr); } }
if (ptButton->fsState & ODS_FOCUS) {
BtnDrawFocusRect(hdc, &rcFocus, ptButton->fsState); } }
/*****************************Private*Routine******************************\
* BtnCreateBitmapButtons * * Returns TRUE if successful, otherwise FALSE; * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ BOOL WINAPI BtnCreateBitmapButtons( HWND hWnd, HINSTANCE hInst, UINT wID, UINT uStyle, LPBITMAPBTN lpButtons, int nButtons, int dxBitmap, int dyBitmap ) { PBTNSTATE pTBState;
/*
** If we have already created Bitmap Buttons for this ** window just return. */ if (GetProp(hWnd, szBbmProp)) { return TRUE; }
CheckSysColors();
/*
** Allocate the required storage and save the pointer in the window ** property list. */ pTBState = (PBTNSTATE)LocalAlloc( LMEM_FIXED, (sizeof(BTNSTATE) - sizeof(BITMAPBTN)) + (nButtons * sizeof(BITMAPBTN)) ); if (pTBState == NULL ) { return FALSE; } SetProp(hWnd, szBbmProp, (HANDLE)pTBState);
pTBState->hInst = hInst; pTBState->wID = wID; pTBState->uStyle = uStyle; pTBState->nButtons = nButtons; pTBState->hbm = CreateMappedBitmap( hInst, wID, TRUE, NULL, 0); pTBState->dxBitmap = dxBitmap; pTBState->dyBitmap = dyBitmap;
InitObjects( pTBState );
CopyMemory( pTBState->Buttons, lpButtons, nButtons * sizeof(BITMAPBTN) );
/*
** Does the caller want tool tips ? */ if (pTBState->uStyle & BBS_TOOLTIPS) {
pTBState->hwndToolTips = CreateWindow(TOOLTIPS_CLASS, g_szEmpty, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hWnd, NULL, hInst, NULL);
if (pTBState->hwndToolTips != (HWND)NULL ) {
int i; TOOLINFO ti;
pTBState->lpfnDefProc = SubclassWindow( hWnd, ParentSubclassProc );
ti.uFlags = 0; ti.cbSize = sizeof(ti); ti.lpszText = LPSTR_TEXTCALLBACK;
for ( i = 0; i < nButtons; i++ ) {
LPBTN_INFO lpBtnInfo; HWND hwndBtn;
hwndBtn = GetDlgItem(hWnd, pTBState->Buttons[i].uId); if ( hwndBtn == (HWND)NULL ) { break; }
lpBtnInfo = (LPBTN_INFO)LocalAlloc(LPTR, sizeof(BTN_INFO)); if (lpBtnInfo == NULL ) { break; }
SetProp(hwndBtn, szButtonProp, (HANDLE)lpBtnInfo); lpBtnInfo->hwndToolTips = pTBState->hwndToolTips; lpBtnInfo->hwndParent = hWnd; lpBtnInfo->lpfnDefProc = SubclassWindow( hwndBtn, ButtonSubclassProc );
ti.hwnd = hwndBtn; ti.uId = pTBState->Buttons[i].uId;
GetClientRect( hwndBtn, &ti.rect ); SendMessage( lpBtnInfo->hwndToolTips, TTM_ADDTOOL, (WPARAM)0, (LPARAM)&ti );
/*
** Add the same rectangle in parent co-ordinates so that ** the tooltip still gets displayed even though the button ** is disabled. */ MapWindowRect( hwndBtn, hWnd, &ti.rect ); ti.hwnd = hWnd; SendMessage( lpBtnInfo->hwndToolTips, TTM_ADDTOOL, (WPARAM)0, (LPARAM)&ti ); }
} else {
/*
** No tips available, just remove the BBS_TOOLTIPS style */ pTBState->uStyle &= ~BBS_TOOLTIPS; } }
return TRUE; }
/******************************Public*Routine******************************\
* BtnDestroyBitmapButtons * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ void WINAPI BtnDestroyBitmapButtons( HWND hwnd ) { PBTNSTATE pTBState;
pTBState = (PBTNSTATE)GetProp(hwnd, szBbmProp); if ( pTBState != NULL ) {
DeleteObject( pTBState->hbm ); FreeObjects( pTBState ); } RemoveProp(hwnd, szBbmProp); }
/******************************Public*Routine******************************\
* BtnDrawFocusRect * * Use this function to draw focus rectangle around a bitmap button. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void WINAPI BtnDrawFocusRect( HDC hdc, const RECT *lpRect, UINT fsState ) { int iFaceOffset; RECT rc;
CopyRect( &rc, lpRect );
rc.top = rc.left = 3;
if (fsState & ODS_SELECTED) { iFaceOffset = 2; } else { iFaceOffset = 4; }
rc.right -= iFaceOffset; rc.bottom -= iFaceOffset;
SetBkColor( hdc, rgbFace ); DrawFocusRect( hdc, &rc ); }
/******************************Public*Routine******************************\
* BtnUpdateColors * * After a WM_SYSCOLORCHANGE message is received this function should be * called to update the colors of the button bitmaps. * * History: * 18-11-93 - StephenE - Created * \**************************************************************************/ void WINAPI BtnUpdateColors( HWND hwnd ) { PBTNSTATE pTBState;
pTBState = (PBTNSTATE)GetProp(hwnd, szBbmProp); if (pTBState->nSysColorChanges != nSysColorChanges) { DeleteObject( pTBState->hbm ); pTBState->hbm = CreateMappedBitmap( pTBState->hInst, pTBState->wID, TRUE, NULL, 0);
pTBState->nSysColorChanges = nSysColorChanges; } }
/******************************Public*Routine******************************\
* ButtonSubclassProc * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ LRESULT CALLBACK ButtonSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { LPBTN_INFO lpBtnInfo; WNDPROC lpfnDefProc;
lpBtnInfo = (LPBTN_INFO)GetProp( hwnd, szButtonProp );
/*
** Save this in case anything happens to lpBtnInfo before we return. */ lpfnDefProc = lpBtnInfo->lpfnDefProc;
switch ( uMsg ) {
case WM_DESTROY: SubclassWindow( hwnd, lpfnDefProc ); if (lpBtnInfo) { LocalFree((HLOCAL)lpBtnInfo); RemoveProp(hwnd, szButtonProp); } break;
case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEMOVE: RelayToToolTips( lpBtnInfo->hwndToolTips, hwnd, uMsg, wParam, lParam ); break;
case WM_MOVE: { TOOLINFO ti;
ti.cbSize = sizeof(ti); ti.uFlags = 0; ti.hwnd = hwnd; ti.lpszText = LPSTR_TEXTCALLBACK; ti.uId = GetDlgCtrlID( hwnd );
GetClientRect( hwnd, &ti.rect );
SendMessage( lpBtnInfo->hwndToolTips, TTM_NEWTOOLRECT, 0, (LPARAM)&ti );
/*
** Add the same rectangle in parent co-ordinates so that ** the tooltip still gets displayed even though the button ** is disabled. */ MapWindowRect( hwnd, lpBtnInfo->hwndParent, &ti.rect ); ti.hwnd = lpBtnInfo->hwndParent; SendMessage( lpBtnInfo->hwndToolTips, TTM_NEWTOOLRECT, (WPARAM)0, (LPARAM)&ti ); } break;
case WM_NOTIFY: SendMessage(lpBtnInfo->hwndParent, WM_NOTIFY, wParam, lParam); break;
}
return CallWindowProc(lpfnDefProc, hwnd, uMsg, wParam, lParam); }
/******************************Public*Routine******************************\
* ParentSubclassProc * * Why do I need to subclass the buttons parent window ? Well, * if a button is disable it will not receive mouse messages, the * messages go to the window underneath the button (ie. the parent). * Therefore we detect this and relay the mouse message to the tool tips * window as above. * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ LRESULT CALLBACK ParentSubclassProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { WNDPROC lpfnDefProc; PBTNSTATE pTBState;
pTBState = (PBTNSTATE)GetProp(hwnd, szBbmProp);
/*
** Save this in case anything happens to lpBtnInfo before we return. */ lpfnDefProc = pTBState->lpfnDefProc;
switch ( uMsg ) {
case TB_GETTOOLTIPS: return (LRESULT)(UINT)pTBState->hwndToolTips;
case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEMOVE: case WM_NCMOUSEMOVE: RelayToToolTips( pTBState->hwndToolTips, hwnd, uMsg, wParam, lParam ); break; }
return CallWindowProc(lpfnDefProc, hwnd, uMsg, wParam, lParam); }
/******************************Public*Routine******************************\
* RelayToToolTips * * * * History: * dd-mm-94 - StephenE - Created * \**************************************************************************/ void FAR PASCAL RelayToToolTips( HWND hwndToolTips, HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam ) { if(hwndToolTips) { MSG msg; msg.lParam = lParam; msg.wParam = wParam; msg.message = wMsg; msg.hwnd = hWnd; SendMessage(hwndToolTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg); } }
|