|
|
/*
** ** Toolbar.c ** ** This is it, the incredibly famous toolbar control. Most of ** the customization stuff is in another file. ** */ #include "ctlspriv.h"
#define Reference(x) ((x)=(x))
#define SZCODE static char _based(_segname("_CODE"))
char aszToolbarClassName[] = TOOLBARCLASSNAME;
SZCODE szUSER[] = "USER.EXE"; SZCODE szDrawFrameControl[] = "DrawFrameControl"; SZCODE szKernel[] = "KERNEL.EXE"; SZCODE szWriteProfileStruct[] = "WritePrivateProfileStruct";
// these values are defined by the UI gods...
#define DEFAULTBITMAPX 16
#define DEFAULTBITMAPY 15
#define DEFAULTBUTTONX 24
#define DEFAULTBUTTONY 22
// horizontal/vertical space taken up by button chisel, sides,
// and a 1 pixel margin. used in GrowToolbar.
#define XSLOP 7
#define YSLOP 6
#define SLOPTOP 1
#define SLOPBOT 1
#define SLOPLFT 8
static int dxButtonSep = 8; static int xFirstButton = SLOPLFT; //!!! was 8
static int iInitCount = 0;
static int nSelectedBM = -1; static HDC hdcGlyphs = NULL; // globals for fast drawing
static HDC hdcMono = NULL; static HBITMAP hbmMono = NULL; static HBITMAP hbmDefault = NULL;
static HDC hdcButton = NULL; // contains hbmFace (when it exists)
static HBITMAP hbmFace = NULL; static int dxFace, dyFace; // current dimensions of hbmFace (2*dxFace)
static HDC hdcFaceCache = NULL; // used for button cache
static HFONT hIconFont = NULL; // font used for strings in buttons
static int yIconFont; // height of the font
static BOOL g_bUseDFC = FALSE; // use DrawFrameControl, if available
static BOOL g_bProfStruct = FALSE; // use PrivateProfileStruct routines
static WORD g_dxOverlap = 1; // overlap between buttons
static WORD wStateMasks[] = { TBSTATE_ENABLED, TBSTATE_CHECKED, TBSTATE_PRESSED, TBSTATE_HIDDEN, TBSTATE_INDETERMINATE };
LRESULT CALLBACK _loadds ToolbarWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
#define HeightWithString(h) (h + yIconFont + 1)
static BOOL NEAR PASCAL InitGlobalObjects(void) { LOGFONT lf; TEXTMETRIC tm; HFONT hOldFont;
iInitCount++;
if (iInitCount != 1) return TRUE;
hdcGlyphs = CreateCompatibleDC(NULL); if (!hdcGlyphs) return FALSE; hdcMono = CreateCompatibleDC(NULL); if (!hdcMono) return FALSE;
hbmMono = CreateBitmap(DEFAULTBUTTONX, DEFAULTBUTTONY, 1, 1, NULL); if (!hbmMono) return FALSE;
hbmDefault = SelectObject(hdcMono, hbmMono);
hdcButton = CreateCompatibleDC(NULL); if (!hdcButton) return FALSE; hdcFaceCache = CreateCompatibleDC(NULL); if (!hdcFaceCache) return FALSE;
SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0); hIconFont = CreateFontIndirect(&lf); if (!hIconFont) return FALSE;
hOldFont = SelectObject(hdcMono, hIconFont); GetTextMetrics(hdcMono, &tm); yIconFont = tm.tmHeight; if (hOldFont) SelectObject(hdcMono, hOldFont);
#if WINVER >= 0x0400
// set a global flag to see if USER will draw for us
if (GetProcAddress(LoadLibrary(szUSER), szDrawFrameControl)) { g_bUseDFC = TRUE; g_dxOverlap = 0; // buttons do NOT overlap with new look
} // set a global flag to see if KERNEL does profile structs
if (GetProcAddress(LoadLibrary(szKernel), szWriteProfileStruct)) g_bProfStruct = TRUE; #endif
return TRUE; }
static BOOL NEAR PASCAL FreeGlobalObjects(void) { iInitCount--;
if (iInitCount != 0) return TRUE;
if (hdcMono) { if (hbmDefault) SelectObject(hdcMono, hbmDefault); DeleteDC(hdcMono); // toast the DCs
} hdcMono = NULL;
if (hdcGlyphs) DeleteDC(hdcGlyphs); hdcGlyphs = NULL; if (hdcFaceCache) DeleteDC(hdcFaceCache); hdcFaceCache = NULL;
if (hdcButton) { if (hbmDefault) SelectObject(hdcButton, hbmDefault); DeleteDC(hdcButton); } hdcButton = NULL;
if (hbmFace) DeleteObject(hbmFace); hbmFace = NULL;
if (hbmMono) DeleteObject(hbmMono); hbmMono = NULL;
if (hIconFont) DeleteObject(hIconFont); hIconFont = NULL; }
HWND WINAPI CreateToolbarEx(HWND hwnd, DWORD ws, WORD wID, int nBitmaps, HINSTANCE hBMInst, WORD wBMID, LPCTBBUTTON lpButtons, int iNumButtons, int dxButton, int dyButton, int dxBitmap, int dyBitmap, UINT uStructSize) {
HWND hwndToolbar;
hwndToolbar = CreateWindow(aszToolbarClassName, NULL, WS_CHILD | ws, 0, 0, 100, 30, hwnd, (HMENU)wID, (HINSTANCE)GetWindowWord(hwnd, GWW_HINSTANCE), NULL); if (!hwndToolbar) goto Error1;
SendMessage(hwndToolbar, TB_BUTTONSTRUCTSIZE, uStructSize, 0L);
if (dxBitmap && dyBitmap) if (!SendMessage(hwndToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(dxBitmap, dyBitmap))) { //!!!! do we actually need to deal with this?
DestroyWindow(hwndToolbar); hwndToolbar = NULL; goto Error1; }
if (dxButton && dyButton) if (!SendMessage(hwndToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(dxButton, dyButton))) { //!!!! do we actually need to deal with this?
DestroyWindow(hwndToolbar); hwndToolbar = NULL; goto Error1; }
SendMessage(hwndToolbar, TB_ADDBITMAP, nBitmaps, MAKELONG(hBMInst, wBMID)); SendMessage(hwndToolbar, TB_ADDBUTTONS, iNumButtons, (LPARAM)lpButtons);
Error1: return hwndToolbar; }
#if 0
/* This is no longer declared in COMMCTRL.H. It only exists for compatibility
** with existing apps; new apps must use CreateToolbarEx. */ HWND WINAPI CreateToolbar(HWND hwnd, DWORD ws, WORD wID, int nBitmaps, HINSTANCE hBMInst, WORD wBMID, LPCTBBUTTON lpButtons, int iNumButtons) { // old-style toolbar, so no divider.
ws |= CCS_NODIVIDER; return (CreateToolbarEx(hwnd, ws, wID, nBitmaps, hBMInst, wBMID, lpButtons, iNumButtons, 0, 0, 0, 0, sizeof(OLDTBBUTTON))); } #endif
BOOL FAR PASCAL InitToolbarClass(HINSTANCE hInstance) { WNDCLASS wc;
if (!GetClassInfo(hInstance, aszToolbarClassName, &wc)) {
wc.lpszClassName = aszToolbarClassName; wc.style = CS_GLOBALCLASS | CS_DBLCLKS; wc.lpfnWndProc = ToolbarWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = sizeof(PTBSTATE); wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); wc.lpszMenuName = NULL;
if (!RegisterClass(&wc)) return FALSE; }
return TRUE; }
#define BEVEL 2
#define FRAME 1
static void NEAR PASCAL 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); }
static void NEAR PASCAL DrawString(HDC hdc, int x, int y, int dx, PSTR pszString) { int oldMode; DWORD oldTextColor; HFONT oldhFont; DWORD dwExt; int len;
oldMode = SetBkMode(hdc, TRANSPARENT); oldTextColor = SetTextColor(hdc, 0L); oldhFont = SelectObject(hdc, hIconFont);
len = lstrlen(pszString); dwExt = GetTextExtent(hdc, (LPSTR)pszString, len); // center the string horizontally
x += (dx - LOWORD(dwExt) - 1)/2;
TextOut(hdc, x, y, (LPSTR)pszString, len);
if (oldhFont) SelectObject(hdc, oldhFont); SetTextColor(hdc, oldTextColor); SetBkMode(hdc, oldMode); }
// create a mono bitmap mask:
// 1's where color == COLOR_BTNFACE || COLOR_HILIGHT
// 0's everywhere else
static void NEAR PASCAL CreateMask(PTBSTATE pTBState, PTBBUTTON pTBButton, int xoffset, int yoffset, int dx, int dy) { PSTR pFoo;
// initalize whole area with 1's
PatBlt(hdcMono, 0, 0, dx, dy, WHITENESS);
// create mask based on color bitmap
// convert this to 1's
SetBkColor(hdcGlyphs, rgbFace); BitBlt(hdcMono, xoffset, yoffset, pTBState->iDxBitmap, pTBState->iDyBitmap, hdcGlyphs, pTBButton->iBitmap * pTBState->iDxBitmap, 0, SRCCOPY); // convert this to 1's
SetBkColor(hdcGlyphs, rgbHilight); // OR in the new 1's
BitBlt(hdcMono, xoffset, yoffset, pTBState->iDxBitmap, pTBState->iDyBitmap, hdcGlyphs, pTBButton->iBitmap * pTBState->iDxBitmap, 0, SRCPAINT);
if (pTBButton->iString != -1 && (pTBButton->iString < pTBState->nStrings)) { pFoo = pTBState->pStrings[pTBButton->iString]; DrawString(hdcMono, 1, yoffset + pTBState->iDyBitmap + 1, dx, pFoo); } }
/* Given a button number, the corresponding bitmap is loaded and selected in,
* and the Window origin set. * Returns NULL on Error, 1 if the necessary bitmap is already selected, * or the old bitmap otherwise. */ static HBITMAP FAR PASCAL SelectBM(HDC hDC, PTBSTATE pTBState, int nButton) { PTBBMINFO pTemp; HBITMAP hRet; int nBitmap, nTot;
for (pTemp=pTBState->pBitmaps, nBitmap=0, nTot=0; ; ++pTemp, ++nBitmap) { if (nBitmap >= pTBState->nBitmaps) return(NULL);
if (nButton < nTot+pTemp->nButtons) break;
nTot += pTemp->nButtons; }
/* Special case when the required bitmap is already selected
*/ if (nBitmap == nSelectedBM) return((HBITMAP)1);
if (!pTemp->hbm || (hRet=SelectObject(hDC, pTemp->hbm))==NULL) { if (pTemp->hbm) DeleteObject(pTemp->hbm);
if (pTemp->hInst) pTemp->hbm = CreateMappedBitmap(pTemp->hInst, pTemp->wID, TRUE, NULL, 0); else pTemp->hbm = (HBITMAP)pTemp->wID;
if (!pTemp->hbm || (hRet=SelectObject(hDC, pTemp->hbm))==NULL) return(NULL); }
nSelectedBM = nBitmap; #ifdef WIN32
SetWindowOrgEx(hDC, nTot * pTBState->iDxBitmap, 0, NULL); #else // WIN32
SetWindowOrg(hDC, nTot * pTBState->iDxBitmap, 0); #endif
return(hRet); }
static void FAR PASCAL DrawBlankButton(HDC hdc, int x, int y, int dx, int dy, WORD state, WORD wButtType) { #if WINVER >= 0x0400
RECT r1; #endif
// face color
PatB(hdc, x, y, dx, dy, rgbFace);
#if WINVER >= 0x0400
if (g_bUseDFC) { r1.left = x; r1.top = y; r1.right = x + dx; r1.bottom = y + dy;
DrawFrameControl(hdc, &r1, wButtType, (state & TBSTATE_PRESSED) ? DFCS_PUSHED : 0); } else #endif
{ if (state & TBSTATE_PRESSED) { PatB(hdc, x + 1, y, dx - 2, 1, rgbFrame); PatB(hdc, x + 1, y + dy - 1, dx - 2, 1, rgbFrame); PatB(hdc, x, y + 1, 1, dy - 2, rgbFrame); PatB(hdc, x + dx - 1, y +1, 1, dy - 2, rgbFrame); PatB(hdc, x + 1, y + 1, 1, dy-2, rgbShadow); PatB(hdc, x + 1, y + 1, dx-2, 1, rgbShadow); } else { PatB(hdc, x + 1, y, dx - 2, 1, rgbFrame); PatB(hdc, x + 1, y + dy - 1, dx - 2, 1, rgbFrame); PatB(hdc, x, y + 1, 1, dy - 2, rgbFrame); PatB(hdc, x + dx - 1, y + 1, 1, dy - 2, rgbFrame); dx -= 2; dy -= 2; PatB(hdc, x + 1, y + 1, 1, dy - 1, rgbHilight); PatB(hdc, x + 1, y + 1, dx - 1, 1, rgbHilight); PatB(hdc, x + dx, y + 1, 1, dy, rgbShadow); PatB(hdc, x + 1, y + dy, dx, 1, rgbShadow); PatB(hdc, x + dx - 1, y + 2, 1, dy - 2, rgbShadow); PatB(hdc, x + 2, y + dy - 1, dx - 2, 1, rgbShadow); } } }
#define DSPDxax 0x00E20746
#define PSDPxax 0x00B8074A
#define FillBkColor(hdc, prc) ExtTextOut(hdc,0,0,ETO_OPAQUE,prc,NULL,0,NULL)
static void NEAR PASCAL DrawFace(PTBSTATE pTBState, PTBBUTTON ptButton, HDC hdc, int x, int y, int offx, int offy, int dx) { PSTR pFoo;
BitBlt(hdc, x + offx, y + offy, pTBState->iDxBitmap, pTBState->iDyBitmap, hdcGlyphs, ptButton->iBitmap * pTBState->iDxBitmap, 0, SRCCOPY);
if (ptButton->iString != -1 && (ptButton->iString < pTBState->nStrings)) { pFoo = pTBState->pStrings[ptButton->iString]; DrawString(hdc, x + 1, y + offy + pTBState->iDyBitmap + 1, dx, pFoo); } }
static void FAR PASCAL DrawButton(HDC hdc, int x, int y, int dx, int dy, PTBSTATE pTBState, PTBBUTTON ptButton, BOOL bFaceCache) { int yOffset; HBRUSH hbrOld, hbr; BOOL bMaskCreated = FALSE; BYTE state; int xButton = 0; // assume button is down
int dxFace, dyFace; int xCenterOffset;
dxFace = dx - 4; dyFace = dy - 4;
// make local copy of state and do proper overriding
state = ptButton->fsState; if (state & TBSTATE_INDETERMINATE) { if (state & TBSTATE_PRESSED) state &= ~TBSTATE_INDETERMINATE; else if (state & TBSTATE_ENABLED) state = TBSTATE_INDETERMINATE; else state &= ~TBSTATE_INDETERMINATE; }
// get the proper button look-- up or down.
if (!(state & (TBSTATE_PRESSED | TBSTATE_CHECKED))) { xButton = dx; // use 'up' version of button
} if (bFaceCache) BitBlt(hdc, x, y, dx, dy, hdcButton, xButton, 0, SRCCOPY); else DrawBlankButton(hdc, x, y, dx, dy, state, pTBState->wButtonType);
// move coordinates inside border and away from upper left highlight.
// the extents change accordingly.
x += 2; y += 2;
if (!SelectBM(hdcGlyphs, pTBState, ptButton->iBitmap)) return;
// calculate offset of face from (x,y). y is always from the top,
// so the offset is easy. x needs to be centered in face.
yOffset = 1; xCenterOffset = (dxFace - pTBState->iDxBitmap)/2; if (state & (TBSTATE_PRESSED | TBSTATE_CHECKED)) { // pressed state moves down and to the right
xCenterOffset++; yOffset++; }
// now put on the face
if (state & TBSTATE_ENABLED) { // regular version
DrawFace(pTBState, ptButton, hdc, x, y, xCenterOffset, yOffset, dxFace); } else { // disabled version (or indeterminate)
bMaskCreated = TRUE; CreateMask(pTBState, ptButton, xCenterOffset, yOffset, dxFace, dyFace);
SetTextColor(hdc, 0L); // 0's in mono -> 0 (for ROP)
SetBkColor(hdc, 0x00FFFFFF); // 1's in mono -> 1
// draw glyph's white understrike
if (!(state & TBSTATE_INDETERMINATE)) { 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, dxFace, dyFace, hdcMono, 0, 0, PSDPxax); SelectObject(hdc, hbrOld); } DeleteObject(hbr); } }
// gray out glyph
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, dxFace, dyFace, hdcMono, 0, 0, PSDPxax); SelectObject(hdc, hbrOld); } DeleteObject(hbr); }
if (state & TBSTATE_CHECKED) { BitBlt(hdcMono, 1, 1, dxFace - 1, dyFace - 1, hdcMono, 0, 0, SRCAND); } }
if (state & (TBSTATE_CHECKED | TBSTATE_INDETERMINATE)) {
hbrOld = SelectObject(hdc, hbrDither); if (hbrOld) {
if (!bMaskCreated) CreateMask(pTBState, ptButton, xCenterOffset, yOffset, dxFace, dyFace);
SetTextColor(hdc, 0L); // 0 -> 0
SetBkColor(hdc, 0x00FFFFFF); // 1 -> 1
// only draw the dither brush where the mask is 1's
BitBlt(hdc, x, y, dxFace, dyFace, hdcMono, 0, 0, DSPDxax); SelectObject(hdc, hbrOld); } } }
static void NEAR PASCAL FlushButtonCache(PTBSTATE pTBState) { if (pTBState->hbmCache) { DeleteObject(pTBState->hbmCache); pTBState->hbmCache = 0; } }
// make sure that hbmMono is big enough to do masks for this
// size of button. if not, fail.
static BOOL NEAR PASCAL CheckMonoMask(int width, int height) { BITMAP bm; HBITMAP hbmTemp;
GetObject(hbmMono, sizeof(BITMAP), &bm); if (width > bm.bmWidth || height > bm.bmHeight) { hbmTemp = CreateBitmap(width, height, 1, 1, NULL); if (!hbmTemp) return FALSE; SelectObject(hdcMono, hbmTemp); DeleteObject(hbmMono); hbmMono = hbmTemp; } return TRUE; }
/*
** GrowToolbar ** ** Attempt to grow the button size. ** ** The calling function can either specify a new internal measurement ** or a new external measurement. */ static BOOL NEAR PASCAL GrowToolbar(PTBSTATE pTBState, int newButWidth, int newButHeight, BOOL bInside) { // if growing based on inside measurement, get full size
if (bInside) { newButHeight += YSLOP; newButWidth += XSLOP; // if toolbar already has strings, don't shrink width it because it
// might clip room for the string
if ((newButWidth < pTBState->iButWidth) && pTBState->nStrings) newButWidth = pTBState->iButWidth; } else { if (newButHeight < pTBState->iButHeight) newButHeight = pTBState->iButHeight; if (newButWidth < pTBState->iButWidth) newButWidth = pTBState->iButWidth; }
// if the size of the toolbar is actually growing, see if shadow
// bitmaps can be made sufficiently large.
if ((newButWidth > pTBState->iButWidth) || (newButHeight > pTBState->iButHeight)) { if (!CheckMonoMask(newButWidth, newButHeight)) return(FALSE); }
pTBState->iButWidth = newButWidth; pTBState->iButHeight = newButHeight;
//!!!ACK ACK ACK ACK
#if 0
// bar height has 2 pixels above, 3 below
pTBState->iBarHeight = pTBState->iButHeight + 5; pTBState->iYPos = 2; #else
pTBState->iBarHeight = pTBState->iButHeight + SLOPTOP+SLOPBOT; pTBState->iYPos = SLOPTOP; #endif
return TRUE; }
static BOOL NEAR PASCAL SetBitmapSize(PTBSTATE pTBState, int width, int height) { int realh = height;
if (pTBState->nStrings) realh = HeightWithString(height);
if (GrowToolbar(pTBState, width, realh, TRUE)) { pTBState->iDxBitmap = width; pTBState->iDyBitmap = height; return TRUE; } return FALSE; }
static void NEAR PASCAL UpdateTBState(PTBSTATE pTBState) { int i; PTBBMINFO pBitmap;
if (pTBState->nSysColorChanges!=nSysColorChanges) { /* Reset all of the bitmaps if the sys colors have changed
* since the last time the bitmaps were created. */ for (i=pTBState->nBitmaps-1, pBitmap=pTBState->pBitmaps; i>=0; --i, ++pBitmap) { if (pBitmap->hInst && pBitmap->hbm) { DeleteObject(pBitmap->hbm); pBitmap->hbm = NULL; } }
FlushButtonCache(pTBState);
// now we're updated to latest color scheme
pTBState->nSysColorChanges = nSysColorChanges; } }
#define CACHE 0x01
#define BUILD 0x02
static void NEAR PASCAL ToolbarPaint(HWND hWnd, PTBSTATE pTBState) { RECT rc; HDC hdc; PAINTSTRUCT ps; int iButton, xButton, yButton; int cButtons = pTBState->iNumButtons; PTBBUTTON pAllButtons = pTBState->Buttons; HBITMAP hbmOldGlyphs; int xCache = 0; WORD wFlags = 0; int iCacheWidth = 0; HBITMAP hbmTemp; BOOL bFaceCache = TRUE; // assume face cache exists
int dx,dy;
CheckSysColors(); UpdateTBState(pTBState);
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc); if (!rc.right) goto Error1;
dx = pTBState->iButWidth; dy = pTBState->iButHeight;
// setup global stuff for fast painting
/* We need to kick-start the bitmap selection process.
*/ nSelectedBM = -1; hbmOldGlyphs = SelectBM(hdcGlyphs, pTBState, 0); if (!hbmOldGlyphs) goto Error1;
yButton = pTBState->iYPos; rc.top = yButton; rc.bottom = yButton + dy;
if (!(pTBState->hbmCache)) { // calculate the width of the cache.
for (iButton = 0; iButton < cButtons; iButton++) { if (!(pAllButtons[iButton].fsState & TBSTATE_HIDDEN) && !(pAllButtons[iButton].fsStyle & TBSTYLE_SEP)) iCacheWidth += pTBState->iButWidth; } pTBState->hbmCache = CreateCompatibleBitmap(hdcGlyphs, iCacheWidth, dy); wFlags |= BUILD;
// if needed, create or enlarge bitmap for pre-building button states
if (!(hbmFace && (dx <= dxFace) && (dy <= dyFace))) { hbmTemp = CreateCompatibleBitmap(hdcGlyphs, 2*dx, dy); if (hbmTemp) { SelectObject(hdcButton, hbmTemp); if (hbmFace) DeleteObject(hbmFace); hbmFace = hbmTemp; dxFace = dx; dyFace = dy; } else bFaceCache = FALSE; } } if (pTBState->hbmCache) { SelectObject(hdcFaceCache,pTBState->hbmCache); wFlags |= CACHE; } else wFlags = 0;
if (bFaceCache) { DrawBlankButton(hdcButton, 0, 0, dx, dy, TBSTATE_PRESSED, pTBState->wButtonType); DrawBlankButton(hdcButton, dx, 0, dx, dy, 0, pTBState->wButtonType); }
for (iButton = 0, xButton = xFirstButton; iButton < cButtons; iButton++) {
PTBBUTTON ptbButton = &pAllButtons[iButton];
if (ptbButton->fsState & TBSTATE_HIDDEN) { /* Do nothing */ ; } else if (ptbButton->fsStyle & TBSTYLE_SEP) { xButton += ptbButton->iBitmap; } else { if (wFlags & BUILD) DrawButton(hdcFaceCache, xCache, 0, dx, dy, pTBState, ptbButton, bFaceCache);
rc.left = xButton; rc.right = xButton + dx; if (RectVisible(hdc, &rc)) { if ((wFlags & CACHE) && !(ptbButton->fsState & TBSTATE_PRESSED)) BitBlt(hdc, xButton, yButton, dx, dy, hdcFaceCache, xCache, 0, SRCCOPY); else DrawButton(hdc, xButton, yButton, dx, dy, pTBState, ptbButton, bFaceCache); } // advance the "pointer" in the cache
xCache += dx;
xButton += (dx - g_dxOverlap); } }
if (wFlags & CACHE) SelectObject(hdcFaceCache, hbmDefault); SelectObject(hdcGlyphs, hbmOldGlyphs);
Error1: EndPaint(hWnd, &ps); }
static BOOL NEAR PASCAL GetItemRect(PTBSTATE pTBState, UINT uButton, LPRECT lpRect) { UINT iButton, xPos; PTBBUTTON pButton;
if (uButton>=(UINT)pTBState->iNumButtons || (pTBState->Buttons[uButton].fsState&TBSTATE_HIDDEN)) { return(FALSE); }
xPos = xFirstButton;
for (iButton=0, pButton=pTBState->Buttons; iButton<uButton; ++iButton, ++pButton) { if (pButton->fsState & TBSTATE_HIDDEN) { /* Do nothing */ ; } else if (pButton->fsStyle & TBSTYLE_SEP) { xPos += pButton->iBitmap; } else { xPos += (pTBState->iButWidth - g_dxOverlap); } }
/* pButton should now point at the required button, and xPos should be
* its left edge. Note that we already checked if the button was * hidden above. */ lpRect->left = xPos; lpRect->right = xPos + (pButton->fsStyle&TBSTYLE_SEP ? pButton->iBitmap : pTBState->iButWidth); lpRect->top = pTBState->iYPos; lpRect->bottom = lpRect->top + pTBState->iButHeight;
return(TRUE); }
static void NEAR PASCAL InvalidateButton(HWND hwnd, PTBSTATE pTBState, PTBBUTTON pButtonToPaint) { RECT rc;
if (GetItemRect(pTBState, pButtonToPaint-pTBState->Buttons, &rc)) { InvalidateRect(hwnd, &rc, FALSE); } }
static int FAR PASCAL TBHitTest(PTBSTATE pTBState, int xPos, int yPos) { int iButton; int cButtons = pTBState->iNumButtons; PTBBUTTON pButton;
xPos -= xFirstButton; if (xPos < 0) return(-1); yPos -= pTBState->iYPos;
for (iButton=0, pButton=pTBState->Buttons; iButton<cButtons; ++iButton, ++pButton) { if (pButton->fsState & TBSTATE_HIDDEN) /* Do nothing */ ; else if (pButton->fsStyle & TBSTYLE_SEP) xPos -= pButton->iBitmap; else xPos -= (pTBState->iButWidth - g_dxOverlap);
if (xPos < 0) { if (pButton->fsStyle&TBSTYLE_SEP || (UINT)yPos>=(UINT)pTBState->iButHeight) break;
return(iButton); } }
return(-1 - iButton); }
static int FAR PASCAL PositionFromID(PTBSTATE pTBState, int id) { int i; int cButtons = pTBState->iNumButtons; PTBBUTTON pAllButtons = pTBState->Buttons;
for (i = 0; i < cButtons; i++) if (pAllButtons[i].idCommand == id) return i; // position found
return -1; // ID not found!
}
// check a radio button by button index.
// the button matching idCommand was just pressed down. this forces
// up all other buttons in the group.
// this does not work with buttons that are forced up with
static void NEAR PASCAL MakeGroupConsistant(HWND hWnd, PTBSTATE pTBState, int idCommand) { int i, iFirst, iLast, iButton; int cButtons = pTBState->iNumButtons; PTBBUTTON pAllButtons = pTBState->Buttons;
iButton = PositionFromID(pTBState, idCommand);
if (iButton < 0) return;
// assertion
// if (!(pAllButtons[iButton].fsStyle & TBSTYLE_CHECK))
// return;
// did the pressed button just go down?
if (!(pAllButtons[iButton].fsState & TBSTATE_CHECKED)) return; // no, can't do anything
// find the limits of this radio group
for (iFirst = iButton; (iFirst > 0) && (pAllButtons[iFirst].fsStyle & TBSTYLE_GROUP); iFirst--) if (!(pAllButtons[iFirst].fsStyle & TBSTYLE_GROUP)) iFirst++;
cButtons--; for (iLast = iButton; (iLast < cButtons) && (pAllButtons[iLast].fsStyle & TBSTYLE_GROUP); iLast++); if (!(pAllButtons[iLast].fsStyle & TBSTYLE_GROUP)) iLast--;
// search for the currently down button and pop it up
for (i = iFirst; i <= iLast; i++) { if (i != iButton) { // is this button down?
if (pAllButtons[i].fsState & TBSTATE_CHECKED) { pAllButtons[i].fsState &= ~TBSTATE_CHECKED; // pop it up
InvalidateButton(hWnd, pTBState, &pAllButtons[i]); break; // only one button is down right?
} } } }
static void NEAR PASCAL DestroyStrings(PTBSTATE pTBState) { PSTR *p; PSTR end = 0, start = 0; int i;
p = pTBState->pStrings; for (i = 0; i < pTBState->nStrings; i++) { if (!(*p < end) && (*p > start)) { start = (*p); end = start + LocalSize((HANDLE)*p); LocalFree((HANDLE)*p); } p++; i++; }
LocalFree((HANDLE)pTBState->pStrings); }
// not needed for MCIWnd
#if 0
#define MAXSTRINGSIZE 1024
static int NEAR PASCAL AddStrings(PTBSTATE pTBState, WPARAM wParam, LPARAM lParam) { int i; DWORD dwExt; HFONT hOldFont; LPSTR lpsz; PSTR pString, psz, ptmp; int numstr; PSTR *pFoo; PSTR *pOffset; char cSeparator; int len; int newWidth;
// read the string as a resource
if (wParam != 0) { pString = (PSTR)LocalAlloc(LPTR, MAXSTRINGSIZE); if (!pString) return -1; i = LoadString((HINSTANCE)wParam, LOWORD(lParam), (LPSTR)pString, MAXSTRINGSIZE); if (!i) { LocalFree(pString); return -1; } // realloc string buffer to actual needed size
LocalReAlloc(pString, i, LMEM_MOVEABLE);
// convert separators to '\0' and count number of strings
cSeparator = *pString; ptmp = pString; pString += 1; for (numstr = 0, psz = pString; i >= psz-pString; *psz ? psz = (PSTR)AnsiNext((LPSTR)psz) : psz++) { if (*psz == cSeparator) { numstr++; *psz = 0; // terminate with 0
}
} } // read explicit string. copy it into local memory, too.
else { // find total length and number of strings
for (i = 0, numstr = 0, lpsz = (LPSTR)lParam;;) { i++; if (*lpsz == 0) { numstr++; if (*(lpsz+1) == 0) break; } lpsz++; } pString = (PSTR)LocalAlloc(LPTR, i); ptmp = pString; if (!pString) return -1; hmemcpy(pString, (void FAR *)lParam, i); }
// make room for increased string pointer table
if (pTBState->pStrings) pFoo = (PSTR *)LocalReAlloc(pTBState->pStrings, (pTBState->nStrings + numstr) * sizeof(PSTR), LMEM_MOVEABLE); else pFoo = (PSTR *)LocalAlloc(LPTR, numstr * sizeof(PSTR)); if (!pFoo) { LocalFree(ptmp); return -1; }
pTBState->pStrings = pFoo; // pointer to next open slot in string index table.
pOffset = pTBState->pStrings + pTBState->nStrings;
hOldFont = SelectObject(hdcMono, hIconFont); // fix up string pointer table to deal with the new strings.
// check if any string is big enough to necessitate a wider button.
newWidth = pTBState->iDxBitmap; for (i = 0; i < numstr; i++, pOffset++) { *pOffset = pString;
len = lstrlen(pString); dwExt = GetTextExtent(hdcMono, pString, len); if ((int)(LOWORD(dwExt)) > newWidth) newWidth = LOWORD(dwExt); pString += len + 1; } if (hOldFont) SelectObject(hdcMono, hOldFont);
// is the world big enough to handle the larger buttons?
if (!GrowToolbar(pTBState, newWidth, HeightWithString(pTBState->iDyBitmap), TRUE)) { // back out changes.
if (pTBState->nStrings == 0) { LocalFree(pTBState->pStrings); pTBState->pStrings = 0; } else pTBState->pStrings = (PSTR *)LocalReAlloc(pTBState->pStrings, pTBState->nStrings * sizeof(PSTR), LMEM_MOVEABLE); LocalFree(ptmp); return -1; }
i = pTBState->nStrings; pTBState->nStrings += numstr; return i; // index of first added string
} #endif
/* Adds a new bitmap to the list of BMs available for this toolbar.
* Returns the index of the first button in the bitmap or -1 if there * was an error. */ static int NEAR PASCAL AddBitmap(PTBSTATE pTBState, int nButtons, HINSTANCE hBMInst, WORD wBMID) { PTBBMINFO pTemp; int nBM, nIndex;
if (pTBState->pBitmaps) { /* Check if the bitmap has already been added
*/ for (nBM=pTBState->nBitmaps, pTemp=pTBState->pBitmaps, nIndex=0; nBM>0; --nBM, ++pTemp) { if (pTemp->hInst==hBMInst && pTemp->wID==wBMID) { /* We already have this bitmap, but have we "registered" all
* the buttons in it? */ if (pTemp->nButtons >= nButtons) return(nIndex); if (nBM == 1) { /* If this is the last bitmap, we can easily increase the
* number of buttons without messing anything up. */ pTemp->nButtons = nButtons; return(nIndex); } }
nIndex += pTemp->nButtons; }
pTemp = (PTBBMINFO)LocalReAlloc(pTBState->pBitmaps, (pTBState->nBitmaps+1)*sizeof(TBBMINFO), LMEM_MOVEABLE); if (!pTemp) return(-1); pTBState->pBitmaps = pTemp; } else { pTBState->pBitmaps = (PTBBMINFO)LocalAlloc(LPTR, sizeof(TBBMINFO)); if (!pTBState->pBitmaps) return(-1); }
pTemp = pTBState->pBitmaps + pTBState->nBitmaps;
pTemp->hInst = hBMInst; pTemp->wID = wBMID; pTemp->nButtons = nButtons; pTemp->hbm = NULL;
++pTBState->nBitmaps;
for (nButtons=0, --pTemp; pTemp>=pTBState->pBitmaps; --pTemp) nButtons += pTemp->nButtons;
return(nButtons); }
static BOOL NEAR PASCAL InsertButtons(HWND hWnd, PTBSTATE pTBState, UINT uWhere, UINT uButtons, LPTBBUTTON lpButtons) { PTBBUTTON pIn, pOut;
if (!pTBState || !pTBState->uStructSize) return(FALSE);
pTBState = (PTBSTATE)LocalReAlloc(pTBState, sizeof(TBSTATE)-sizeof(TBBUTTON) + (pTBState->iNumButtons+uButtons)*sizeof(TBBUTTON), LMEM_MOVEABLE); if (!pTBState) return(FALSE);
SETWINDOWPOINTER(hWnd, PTBSTATE, pTBState);
if (uWhere > (UINT)pTBState->iNumButtons) uWhere = pTBState->iNumButtons;
for (pIn=pTBState->Buttons+pTBState->iNumButtons-1, pOut=pIn+uButtons, uWhere=(UINT)pTBState->iNumButtons-uWhere; uWhere>0; --pIn, --pOut, --uWhere) *pOut = *pIn;
for (lpButtons=(LPTBBUTTON)((LPSTR)lpButtons+pTBState->uStructSize*(uButtons-1)), pTBState->iNumButtons+=(int)uButtons; uButtons>0; --pOut, lpButtons=(LPTBBUTTON)((LPSTR)lpButtons-pTBState->uStructSize), --uButtons) { TBInputStruct(pTBState, pOut, lpButtons);
if ((pOut->fsStyle&TBSTYLE_SEP) && pOut->iBitmap<=0) pOut->iBitmap = dxButtonSep; } // flush the cache
FlushButtonCache(pTBState);
/* We need to completely redraw the toolbar at this point.
*/ InvalidateRect(hWnd, NULL, TRUE);
return(TRUE); }
/* Notice that the state structure is not realloc'ed smaller at this
* point. This is a time optimization, and the fact that the structure * will not move is used in other places. */ static BOOL NEAR PASCAL DeleteButton(HWND hWnd, PTBSTATE pTBState, UINT uIndex) { PTBBUTTON pIn, pOut;
if (uIndex >= (UINT)pTBState->iNumButtons) return(FALSE);
--pTBState->iNumButtons; for (pOut=pTBState->Buttons+uIndex, pIn=pOut+1; uIndex<(UINT)pTBState->iNumButtons; ++uIndex, ++pIn, ++pOut) *pOut = *pIn;
// flush the cache
FlushButtonCache(pTBState);
/* We need to completely redraw the toolbar at this point.
*/ InvalidateRect(hWnd, NULL, TRUE);
return(TRUE); }
static void FAR PASCAL TBInputStruct(PTBSTATE pTBState, LPTBBUTTON pButtonInt, LPTBBUTTON pButtonExt) { if (pTBState->uStructSize >= sizeof(TBBUTTON)) { *pButtonInt = *pButtonExt; } else /* It is assumed the only other possibility is the OLDBUTTON struct */ { *(LPOLDTBBUTTON)pButtonInt = *(LPOLDTBBUTTON)pButtonExt; /* We don't care about dwData */ pButtonInt->iString = -1; } }
static void FAR PASCAL TBOutputStruct(PTBSTATE pTBState, LPTBBUTTON pButtonInt, LPTBBUTTON pButtonExt) { if (pTBState->uStructSize >= sizeof(TBBUTTON)) { LPSTR pOut; int i;
/* Fill the part we know about and fill the rest with 0's
*/ *pButtonExt = *pButtonInt; for (i=pTBState->uStructSize-sizeof(TBBUTTON), pOut=(LPSTR)(pButtonExt+1); i>0; --i, ++pOut) { *pOut = 0; } } else /* It is assumed the only other possibility is the OLDBUTTON struct */ { *(LPOLDTBBUTTON)pButtonExt = *(LPOLDTBBUTTON)pButtonInt; } }
LRESULT CALLBACK _loadds ToolbarWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam) { BOOL fSameButton; PTBBUTTON ptbButton; PTBSTATE pTBState; int iPos; BYTE fsState; #if WINVER >= 0x0400
DWORD dw; #endif
pTBState = GETWINDOWPOINTER(hWnd, PTBSTATE);
switch (wMsg) { case WM_CREATE:
#define lpcs ((LPCREATESTRUCT)lParam)
if (!CreateDitherBrush(FALSE)) return -1;
if (!InitGlobalObjects()) { FreeGlobalObjects(); return -1; }
/* create the state data for this toolbar */
pTBState = ALLOCWINDOWPOINTER(PTBSTATE, sizeof(TBSTATE)-sizeof(TBBUTTON)); if (!pTBState) return -1;
/* The struct is initialized to all NULL when created.
*/ pTBState->hwndCommand = lpcs->hwndParent;
pTBState->uStructSize = 0;
// grow the button size to the appropriate girth
if (!SetBitmapSize(pTBState, DEFAULTBITMAPX, DEFAULTBITMAPX)) return -1;
SETWINDOWPOINTER(hWnd, PTBSTATE, pTBState);
if (!(lpcs->style&(CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM))) { lpcs->style |= CCS_TOP; SetWindowLong(hWnd, GWL_STYLE, lpcs->style); } break;
case WM_DESTROY: if (pTBState) { PTBBMINFO pTemp; int i;
/* Free all the bitmaps before exiting
*/ for (pTemp=pTBState->pBitmaps, i=pTBState->nBitmaps-1; i>=0; ++pTemp, --i) { if (pTemp->hInst && pTemp->hbm) DeleteObject(pTemp->hbm); } FlushButtonCache(pTBState); if (pTBState->nStrings > 0) DestroyStrings(pTBState);
FREEWINDOWPOINTER(pTBState); SETWINDOWPOINTER(hWnd, PTBSTATE, 0); } FreeGlobalObjects(); FreeDitherBrush(); break;
case WM_NCCALCSIZE: #if WINVER >= 0x0400
/*
* This is sent when the window manager wants to find out * how big our client area is to be. If we have a mini-caption * then we trap this message and calculate the cleint area rect, * which is the client area rect calculated by DefWindowProc() * minus the width/height of the mini-caption bar */ // let defwindowproc handle the standard borders etc...
dw = DefWindowProc(hWnd, wMsg, wParam, lParam ) ;
if (!(GetWindowLong(hWnd, GWL_STYLE) & CCS_NODIVIDER)) { NCCALCSIZE_PARAMS FAR *lpNCP; lpNCP = (NCCALCSIZE_PARAMS FAR *)lParam; lpNCP->rgrc[0].top += 2; }
return dw; #endif
break;
case WM_NCACTIVATE: case WM_NCPAINT:
#if WINVER >= 0x0400
// old-style toolbars are forced to be without dividers above
if (!(GetWindowLong(hWnd, GWL_STYLE) & CCS_NODIVIDER)) { HDC hdc; RECT rc;
hdc = GetWindowDC(hWnd); GetWindowRect(hWnd, &rc); ScreenToClient(hWnd, (LPPOINT)&(rc.left)); ScreenToClient(hWnd, (LPPOINT)&(rc.right)); rc.bottom = (-rc.top); // bottom of NC area
rc.top = rc.bottom - (2 * GetSystemMetrics(SM_CYBORDER));
DrawBorder(hdc, &rc, BDR_SUNKENOUTER, BF_TOP | BF_BOTTOM); ReleaseDC(hWnd, hdc); } else goto DoDefault; #endif
break;
case WM_PAINT: ToolbarPaint(hWnd, pTBState); break;
#if 0
case TB_AUTOSIZE: case WM_SIZE: { RECT rc; HWND hwndParent;
GetWindowRect(hWnd, &rc); rc.right -= rc.left; rc.bottom -= rc.top;
/* If there is no parent, then this is a top level window
*/ hwndParent = GetParent(hWnd); if (hwndParent) ScreenToClient(hwndParent, (LPPOINT)&rc);
NewSize(hWnd, pTBState->iBarHeight, GetWindowLong(hWnd, GWL_STYLE), rc.left, rc.top, rc.right, rc.bottom); break; } #endif
case WM_HSCROLL: //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
case WM_COMMAND: case WM_DRAWITEM: case WM_MEASUREITEM: case WM_VKEYTOITEM: case WM_CHARTOITEM: SendMessage(pTBState->hwndCommand, wMsg, wParam, lParam); break;
case WM_CTLCOLOR: //!!!!! ack use COLOR_BTNFACE
return (LRESULT)(UINT)GetStockObject(LTGRAY_BRUSH);
#if 0
case WM_LBUTTONDBLCLK: iPos = TBHitTest(pTBState, LOWORD(lParam), HIWORD(lParam)); if (iPos<0 && (GetWindowLong(hWnd, GWL_STYLE)&CCS_ADJUSTABLE)) { iPos = -1 - iPos; CustomizeTB(hWnd, pTBState, iPos); } break; #endif
case WM_LBUTTONDOWN:
iPos = TBHitTest(pTBState, LOWORD(lParam), HIWORD(lParam)); #if 0
if ((wParam&MK_SHIFT) &&(GetWindowLong(hWnd, GWL_STYLE)&CCS_ADJUSTABLE)) { MoveButton(hWnd, pTBState, iPos); } else #endif
if (iPos >= 0) { ptbButton = pTBState->Buttons + iPos;
pTBState->pCaptureButton = ptbButton; SetCapture(hWnd);
if (ptbButton->fsState & TBSTATE_ENABLED) { ptbButton->fsState |= TBSTATE_PRESSED; InvalidateButton(hWnd, pTBState, ptbButton); UpdateWindow(hWnd); // imedeate feedback
}
SendMessage(pTBState->hwndCommand, WM_COMMAND, GETWINDOWID(hWnd), MAKELONG(pTBState->pCaptureButton->idCommand, TBN_BEGINDRAG)); } break;
case WM_MOUSEMOVE: // if the toolbar has lost the capture for some reason, stop
if (hWnd != GetCapture()) { SendMessage(pTBState->hwndCommand, WM_COMMAND, GETWINDOWID(hWnd), MAKELONG(pTBState->pCaptureButton->idCommand, TBN_ENDDRAG)); // if the button is still pressed, unpress it.
if (pTBState->pCaptureButton->fsState & TBSTATE_PRESSED) SendMessage(hWnd, TB_PRESSBUTTON, pTBState->pCaptureButton->idCommand, 0L); pTBState->pCaptureButton = NULL; } else if (pTBState->pCaptureButton!=NULL && (pTBState->pCaptureButton->fsState & TBSTATE_ENABLED)) {
iPos = TBHitTest(pTBState, LOWORD(lParam), HIWORD(lParam)); fSameButton = (iPos>=0 && pTBState->pCaptureButton==pTBState->Buttons+iPos); if (fSameButton == !(pTBState->pCaptureButton->fsState & TBSTATE_PRESSED)) { pTBState->pCaptureButton->fsState ^= TBSTATE_PRESSED; InvalidateButton(hWnd, pTBState, pTBState->pCaptureButton); } } break;
case WM_LBUTTONUP: if (pTBState->pCaptureButton != NULL) {
int idCommand;
idCommand = pTBState->pCaptureButton->idCommand;
ReleaseCapture();
SendMessage(pTBState->hwndCommand, WM_COMMAND, GETWINDOWID(hWnd), MAKELONG(idCommand, TBN_ENDDRAG));
iPos = TBHitTest(pTBState, LOWORD(lParam), HIWORD(lParam)); if ((pTBState->pCaptureButton->fsState&TBSTATE_ENABLED) && iPos>=0 && (pTBState->pCaptureButton==pTBState->Buttons+iPos)) { pTBState->pCaptureButton->fsState &= ~TBSTATE_PRESSED;
if (pTBState->pCaptureButton->fsStyle & TBSTYLE_CHECK) { if (pTBState->pCaptureButton->fsStyle & TBSTYLE_GROUP) {
// group buttons already checked can't be force
// up by the user.
if (pTBState->pCaptureButton->fsState & TBSTATE_CHECKED) { pTBState->pCaptureButton = NULL; break; // bail!
}
pTBState->pCaptureButton->fsState |= TBSTATE_CHECKED; MakeGroupConsistant(hWnd, pTBState, idCommand); } else { pTBState->pCaptureButton->fsState ^= TBSTATE_CHECKED; // toggle
} // if we change a button's state, we need to flush the
// cache
FlushButtonCache(pTBState); } InvalidateButton(hWnd, pTBState, pTBState->pCaptureButton); pTBState->pCaptureButton = NULL; SendMessage(pTBState->hwndCommand, WM_COMMAND, idCommand, 0L); } else { pTBState->pCaptureButton = NULL; } } break;
case TB_SETSTATE: iPos = PositionFromID(pTBState, (int)wParam); if (iPos < 0) return(FALSE); ptbButton = pTBState->Buttons + iPos;
fsState = (BYTE)(LOWORD(lParam) ^ ptbButton->fsState); ptbButton->fsState = (BYTE)LOWORD(lParam);
if (fsState) // flush the button cache
//!!!! this could be much more intelligent
FlushButtonCache(pTBState);
if (fsState & TBSTATE_HIDDEN) InvalidateRect(hWnd, NULL, TRUE); else if (fsState) InvalidateButton(hWnd, pTBState, ptbButton); return(TRUE);
case TB_GETSTATE: iPos = PositionFromID(pTBState, (int)wParam); if (iPos < 0) return(-1L); return(pTBState->Buttons[iPos].fsState);
case TB_ENABLEBUTTON: case TB_CHECKBUTTON: case TB_PRESSBUTTON: case TB_HIDEBUTTON: case TB_INDETERMINATE:
iPos = PositionFromID(pTBState, (int)wParam); if (iPos < 0) return(FALSE); ptbButton = &pTBState->Buttons[iPos]; fsState = ptbButton->fsState;
if (LOWORD(lParam)) ptbButton->fsState |= wStateMasks[wMsg - TB_ENABLEBUTTON]; else ptbButton->fsState &= ~wStateMasks[wMsg - TB_ENABLEBUTTON];
// did this actually change the state?
if (fsState != ptbButton->fsState) { // is this button a member of a group?
if ((wMsg == TB_CHECKBUTTON) && (ptbButton->fsStyle & TBSTYLE_GROUP)) MakeGroupConsistant(hWnd, pTBState, (int)wParam);
// flush the button cache
//!!!! this could be much more intelligent
FlushButtonCache(pTBState);
if (wMsg == TB_HIDEBUTTON) InvalidateRect(hWnd, NULL, TRUE); else InvalidateButton(hWnd, pTBState, ptbButton); } return(TRUE);
case TB_ISBUTTONENABLED: case TB_ISBUTTONCHECKED: case TB_ISBUTTONPRESSED: case TB_ISBUTTONHIDDEN: case TB_ISBUTTONINDETERMINATE: iPos = PositionFromID(pTBState, (int)wParam); if (iPos < 0) return(-1L); return (LRESULT)pTBState->Buttons[iPos].fsState & wStateMasks[wMsg - TB_ISBUTTONENABLED];
case TB_ADDBITMAP: return(AddBitmap(pTBState, wParam, (HINSTANCE)LOWORD(lParam), HIWORD(lParam)));
#if 0 // not needed for MCIWnd
case TB_ADDSTRING: return(AddStrings(pTBState, wParam, lParam)); #endif
case TB_ADDBUTTONS: return(InsertButtons(hWnd, pTBState, (UINT)-1, wParam, (LPTBBUTTON)lParam));
case TB_INSERTBUTTON: return(InsertButtons(hWnd, pTBState, wParam, 1, (LPTBBUTTON)lParam));
case TB_DELETEBUTTON: return(DeleteButton(hWnd, pTBState, wParam));
case TB_GETBUTTON: if (wParam >= (UINT)pTBState->iNumButtons) return(FALSE);
TBOutputStruct(pTBState, pTBState->Buttons+wParam, (LPTBBUTTON)lParam); return(TRUE);
case TB_BUTTONCOUNT: return(pTBState->iNumButtons);
case TB_COMMANDTOINDEX: return(PositionFromID(pTBState, (int)wParam));
#if 0
case TB_SAVERESTORE: return(SaveRestore(hWnd, pTBState, wParam, (LPSTR FAR *)lParam));
case TB_CUSTOMIZE: CustomizeTB(hWnd, pTBState, pTBState->iNumButtons); break; #endif
case TB_GETITEMRECT: return(MAKELRESULT(GetItemRect(pTBState, wParam, (LPRECT)lParam), 0)); break;
case TB_BUTTONSTRUCTSIZE: /* You are not allowed to change this after adding buttons.
*/ if (!pTBState || pTBState->iNumButtons) { break; } pTBState->uStructSize = wParam; break;
case TB_SETBUTTONSIZE: if (!LOWORD(lParam)) lParam = MAKELONG(DEFAULTBUTTONX, HIWORD(lParam)); if (!HIWORD(lParam)) lParam = MAKELONG(LOWORD(lParam), DEFAULTBUTTONY); return(GrowToolbar(pTBState, LOWORD(lParam), HIWORD(lParam), FALSE));
case TB_SETBITMAPSIZE: return(SetBitmapSize(pTBState, LOWORD(lParam), HIWORD(lParam)));
case TB_SETBUTTONTYPE: pTBState->wButtonType = wParam; break;
default: #if WINVER >= 0x0400
DoDefault: #endif
return DefWindowProc(hWnd, wMsg, wParam, lParam); }
return 0L; }
|