FLATTB.CPP

//**************************************************************************** 
// Module: Chappy.EXE
// File: FlatTB.cpp
//
//
// Copyright (c) Microsoft Corporation 1996-1997
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//****************************************************************************

#include "stdafx.h"
#define _AFX_NO_OLE_SUPPORT
#include <afxpriv.h>
#include "flatTB.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define new DEBUG_NEW

// globals for fast drawing (shared globals)
#ifndef _MAC
static HDC hDCGlyphs = NULL;
static HDC hDCMono = NULL;
#else
#define hDCGlyphs m_hDCGlyphs
#define hDCMono m_hDCMono
#endif
static HBRUSH hbrDither = NULL;

/////////////////////////////////////////////////////////////////////////////
// Init / Term

#ifndef _MAC
static HBITMAP AFXAPI CreateDitherBitmap();
#else
static HBITMAP AFXAPI CreateDitherBitmap(BOOL bMonochrome);
#endif

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif



// a special struct that will cleanup automatically
struct _AFX_TOOLBAR_TERM
{
~_AFX_TOOLBAR_TERM()
{
#ifndef _MAC
AfxDeleteObject((HGDIOBJ*)&hDCMono);
AfxDeleteObject((HGDIOBJ*)&hDCGlyphs);
#endif
AfxDeleteObject((HGDIOBJ*)&hbrDither);
}
};

static const _AFX_TOOLBAR_TERM toolbarTerm;

/////////////////////////////////////////////////////////////////////////////

#ifdef AFX_CORE3_SEG
#pragma code_seg(AFX_CORE3_SEG)
#endif

// TONYCL: START: OFFICE97 LOOK AND FEEL

struct CToolBarData
{
WORD wVersion;
WORD wWidth;
WORD wHeight;
WORD wItemCount;
//WORD aItems[wItemCount]

WORD* items()
{ return (WORD*)(this+1); }
};

// Support loading a toolbar from a resource
BOOL CFlatToolbar::LoadToolBar(LPCTSTR lpszResourceName)
{
ASSERT_VALID(this);
ASSERT(lpszResourceName != NULL);

// determine location of the bitmap in resource fork
HINSTANCE hInst = AfxFindResourceHandle(lpszResourceName, RT_TOOLBAR);
HRSRC hRsrc = ::FindResource(hInst, lpszResourceName, RT_TOOLBAR);
if (hRsrc == NULL)
return FALSE;

HGLOBAL hGlobal = LoadResource(hInst, hRsrc);
if (hGlobal == NULL)
return FALSE;

CToolBarData* pData = (CToolBarData*)LockResource(hGlobal);
if (pData == NULL)
return FALSE;
ASSERT(pData->wVersion == 1);

UINT* pItems = new UINT[pData->wItemCount];
for (int i = 0; i < pData->wItemCount; i++)
pItems[i] = pData->items()[i];
BOOL bResult = SetButtons(pItems, pData->wItemCount);
delete[] pItems;

if (bResult)
{
// set new sizes of the buttons
CSize sizeImage(pData->wWidth, pData->wHeight);
CSize sizeButton(pData->wWidth + 7, pData->wHeight + 7);
SetSizes(sizeButton, sizeImage);

// load bitmap now that sizes are known by the toolbar control
bResult = LoadBitmap(lpszResourceName);
}

UnlockResource(hGlobal);
FreeResource(hGlobal);

return bResult;
}
// TONYCL: END: OFFICE97 LOOK AND FEEL

#ifndef _MAC
static HBITMAP AFXAPI CreateDitherBitmap()
#else
static HBITMAP AFXAPI CreateDitherBitmap(BOOL bMonochrome)
#endif
{
struct // BITMAPINFO with 16 colors
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[16];
} bmi;
memset(&bmi, 0, sizeof(bmi));

bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 8;
bmi.bmiHeader.biHeight = 8;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 1;
bmi.bmiHeader.biCompression = BI_RGB;

COLORREF clr = ::GetSysColor(COLOR_BTNFACE);
#ifdef _MAC
// if monochrome or the face color is already white, use black instead to make
// sure that we draw a dither - otherwise we'll have a white on white bitmap
if (bMonochrome || clr == RGB(255, 255, 255))
clr = 0;
#endif
bmi.bmiColors[0].rgbBlue = GetBValue(clr);
bmi.bmiColors[0].rgbGreen = GetGValue(clr);
bmi.bmiColors[0].rgbRed = GetRValue(clr);

clr = ::GetSysColor(COLOR_BTNHIGHLIGHT);
bmi.bmiColors[1].rgbBlue = GetBValue(clr);
bmi.bmiColors[1].rgbGreen = GetGValue(clr);
bmi.bmiColors[1].rgbRed = GetRValue(clr);

// initialize the brushes
long patGray[8];
for (int i = 0; i < 8; i++)
patGray[i] = (i & 1) ? 0xAAAA5555L : 0x5555AAAAL;

HDC hDC = GetDC(NULL);
HBITMAP hbm = CreateDIBitmap(hDC, &bmi.bmiHeader, CBM_INIT,
(LPBYTE)patGray, (LPBITMAPINFO)&bmi, DIB_RGB_COLORS);
ReleaseDC(NULL, hDC);

return hbm;
}

// create a mono bitmap mask:
void CFlatToolbar::CreateMask(int iImage, CPoint ptOffset,
BOOL bHilite, BOOL bHiliteShadow)
{
// initalize whole area with 0's
PatBlt(hDCMono, 0, 0, m_sizeButton.cx-2, m_sizeButton.cy-2, WHITENESS);

// create mask based on color bitmap
// convert this to 1's
SetBkColor(hDCGlyphs, globalData.clrBtnFace);
BitBlt(hDCMono, ptOffset.x, ptOffset.y, m_sizeImage.cx, m_sizeImage.cy,
hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);

if (bHilite)
{
// convert this to 1's
SetBkColor(hDCGlyphs, globalData.clrBtnHilite);

// OR in the new 1's
BitBlt(hDCMono, ptOffset.x, ptOffset.y, m_sizeImage.cx, m_sizeImage.cy,
hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCPAINT);

if (bHiliteShadow)
BitBlt(hDCMono, 1, 1, m_sizeButton.cx-3, m_sizeButton.cy-3,
hDCMono, 0, 0, SRCAND);
}
}

// Raster Ops
#define ROP_DSPDxax 0x00E20746L
#define ROP_PSDPxax 0x00B8074AL

BOOL CFlatToolbar::DrawButton(CDC* pDC, int x, int y, int iImage, UINT nStyle)
{
ASSERT_VALID(pDC);

int dx = m_sizeButton.cx;
int dy = m_sizeButton.cy;
if (!globalData.bWin4)
{
// make the coordinates the interior of the button
x += 1;
y += 1;
dx -= 2;
dy -= 2;

// border around button
pDC->FillSolidRect(x, y-1, dx, 1, globalData.clrWindowFrame);
pDC->FillSolidRect(x, y+dy, dx, 1, globalData.clrWindowFrame);
pDC->FillSolidRect(x-1, y, 1, dy, globalData.clrWindowFrame);
pDC->FillSolidRect(x+dx, y, 1, dy, globalData.clrWindowFrame);
}

#ifdef _MAC
if (m_bMonochrome)
return DrawMonoButton(pDC, x, y, dx, dy, iImage, nStyle);
#endif

// interior grey
pDC->FillSolidRect(x, y, dx, dy, globalData.clrBtnFace);

// determine offset of bitmap (centered within button)
CPoint ptOffset;
ptOffset.x = (dx - m_sizeImage.cx - 1) / 2;
ptOffset.y = (dy - m_sizeImage.cy) / 2;

if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
{
// pressed in or checked
pDC->Draw3dRect(x, y, dx, dy,
globalData.bWin4 ? globalData.clrWindowFrame : globalData.clrBtnShadow,
globalData.bWin4 ? globalData.clrBtnHilite : globalData.clrBtnFace);

/* TONYCL: OFFICE97 LOOK AND FEEL
if (globalData.bWin4)
{
pDC->Draw3dRect(x + 1, y + 1, dx - 2, dy - 2,
globalData.clrBtnShadow, globalData.clrBtnFace);
}
*/

// for any depressed button, add one to the offsets.
ptOffset.x += 1;
ptOffset.y += 1;
}
// TONYCL: START: OFFICE97 LOOK AND FEEL
if (nStyle & TBBS_UPSTATE)
{
pDC->Draw3dRect(x, y, dx, dy, globalData.clrBtnHilite,
globalData.bWin4 ? globalData.clrWindowFrame : globalData.clrBtnShadow);
}
// TONYCL: END: OFFICE97 LOOK AND FEEL

if ((nStyle & TBBS_PRESSED) || !(nStyle & TBBS_DISABLED))
{
// normal image version
BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y,
m_sizeImage.cx, m_sizeImage.cy,
hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);

if (nStyle & TBBS_PRESSED)
return TRUE; // nothing more to do (rest of style is ignored)
}

if (nStyle & (TBBS_DISABLED | TBBS_INDETERMINATE))
{
// disabled or indeterminate version
CreateMask(iImage, ptOffset, TRUE, FALSE);

pDC->SetTextColor(0L); // 0's in mono -> 0 (for ROP)
pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1's in mono -> 1

if (nStyle & TBBS_DISABLED)
{
// disabled - draw the hilighted shadow
HGDIOBJ hbrOld = pDC->SelectObject(globalData.hbrBtnHilite);
if (hbrOld != NULL)
{
// draw hilight color where we have 0's in the mask
BitBlt(pDC->m_hDC, x + 1, y + 1,
m_sizeButton.cx - 2, m_sizeButton.cy - 2,
hDCMono, 0, 0, ROP_PSDPxax);
pDC->SelectObject(hbrOld);
}
}

//BLOCK: always draw the shadow
{
HGDIOBJ hbrOld = pDC->SelectObject(globalData.hbrBtnShadow);
if (hbrOld != NULL)
{
// draw the shadow color where we have 0's in the mask
BitBlt(pDC->m_hDC, x, y,
m_sizeButton.cx - 2, m_sizeButton.cy - 2,
hDCMono, 0, 0, ROP_PSDPxax);
pDC->SelectObject(hbrOld);
}
}
}

// if it is checked do the dither brush avoiding the glyph
if (nStyle & (TBBS_CHECKED | TBBS_INDETERMINATE))
{
HGDIOBJ hbrOld = pDC->SelectObject(hbrDither);
if (hbrOld != NULL)
{
ptOffset.x -= globalData.cxBorder2;
ptOffset.y -= globalData.cyBorder2;
CreateMask(iImage, ptOffset, ~(nStyle & TBBS_INDETERMINATE),
nStyle & TBBS_DISABLED);

pDC->SetTextColor(0L); // 0 -> 0
pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1 -> 1

ASSERT(globalData.cxBorder2 == globalData.cyBorder2);
int delta = (nStyle & TBBS_INDETERMINATE) ?
globalData.bWin4 ? globalData.cxBorder2*2 : 3 : globalData.cxBorder2*2;

// only draw the dither brush where the mask is 1's
BitBlt(pDC->m_hDC,
x + globalData.cxBorder2, y + globalData.cyBorder2, dx-delta, dy-delta,
hDCMono, 0, 0, ROP_DSPDxax);
pDC->SelectObject(hbrOld);
}
}

return TRUE;
}

#ifdef _MAC
BOOL CFlatToolbar::DrawMonoButton(CDC* pDC, int x, int y, int dx, int dy,
int iImage, UINT nStyle)
{
// interior is black if pressed, white if not
if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
{
pDC->FillSolidRect(x, y, dx, dy, RGB(0, 0, 0));
pDC->SetBkColor(RGB(255, 255, 255)); // bkcolor was set by PatB
}
else
{
pDC->FillSolidRect(x, y, dx, dy, RGB(0xFF, 0xFF, 0xFF));
}

CPoint ptOffset;
ptOffset.x = (dx - m_sizeImage.cx - 1) / 2;
ptOffset.y = (dy - m_sizeImage.cy) / 2;

if ((nStyle & TBBS_PRESSED) || !(nStyle & TBBS_DISABLED))
{
// normal image version
BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y, m_sizeImage.cx,
m_sizeImage.cy, hDCGlyphs, iImage * m_sizeImage.cx, 0,
(nStyle & (TBBS_PRESSED | TBBS_CHECKED)) ? NOTSRCCOPY : SRCCOPY);

if (nStyle & (TBBS_PRESSED | TBBS_CHECKED))
return TRUE; // nothing more to do (rest of style is ignored)
}

if (nStyle & TBBS_DISABLED)
{
BitBlt(pDC->m_hDC, x + ptOffset.x, y + ptOffset.y, m_sizeImage.cx,
m_sizeImage.cy, hDCGlyphs, iImage * m_sizeImage.cx, 0, SRCCOPY);

int ropOld = pDC->SetROP2(R2_MASKNOTPEN);
RECT rect;
SetRect(&rect, 0, 0, m_sizeImage.cx, m_sizeImage.cy);
OffsetRect(&rect, x + ptOffset.x, y + ptOffset.y);
AfxFillRect(pDC->m_hDC, &rect, hbrDither);
pDC->SetROP2(ropOld);

return TRUE;
}

// if it is checked do the dither brush avoiding the glyph
if (nStyle & (TBBS_CHECKED | TBBS_INDETERMINATE))
{
HGDIOBJ hbrOld = pDC->SelectObject(hbrDither);
if (hbrOld != NULL)
{
CreateMask(iImage, ptOffset, ~(nStyle & TBBS_INDETERMINATE),
nStyle & TBBS_DISABLED);

pDC->SetTextColor(0L); // 0 -> 0
pDC->SetBkColor((COLORREF)0x00FFFFFFL); // 1 -> 1

int delta = (nStyle & TBBS_INDETERMINATE) ? 3 : 1;

// only draw the dither brush where the mask is 1's
CRect rect(0, 0, dx, dy);
::InvertRect(hDCMono, &rect);

BitBlt(pDC->m_hDC, x, y, dx, dy, hDCMono, 0, 0, ROP_PSDPxax);
pDC->SelectObject(hbrOld);
}
}

return TRUE;
}
#endif

BOOL CFlatToolbar::PrepareDrawButton(DrawState& ds)
{
ASSERT(m_hbmImageWell != NULL);
ASSERT(m_sizeButton.cx > 2 && m_sizeButton.cy > 2);

// We need to kick-start the bitmap selection process.
ds.hbmOldGlyphs = (HBITMAP)SelectObject(hDCGlyphs, m_hbmImageWell);
ds.hbmMono = CreateBitmap(m_sizeButton.cx-2, m_sizeButton.cy-2,
1, 1, NULL);
ds.hbmMonoOld = (HBITMAP)SelectObject(hDCMono, ds.hbmMono);
if (ds.hbmOldGlyphs == NULL || ds.hbmMono == NULL || ds.hbmMonoOld == NULL)
{
TRACE0("Error: can't draw toolbar.\n");
AfxDeleteObject((HGDIOBJ*)&ds.hbmMono);
return FALSE;
}
return TRUE;
}

void CFlatToolbar::EndDrawButton(DrawState& ds)
{
SelectObject(hDCMono, ds.hbmMonoOld);
AfxDeleteObject((HGDIOBJ*)&ds.hbmMono);
SelectObject(hDCGlyphs, ds.hbmOldGlyphs);
}

/////////////////////////////////////////////////////////////////////////////
// CFlatToolbar creation etc

struct AFX_TBBUTTON
{
UINT nID; // Command ID that this button sends
UINT nStyle; // TBBS_ styles
int iImage; // index into mondo bitmap of this button's picture
// or size of this spacer
};

inline AFX_TBBUTTON* CFlatToolbar::_GetButtonPtr(int nIndex) const
{
ASSERT(nIndex >= 0 && nIndex < m_nCount);
ASSERT(m_pData != NULL);
return ((AFX_TBBUTTON*)m_pData) + nIndex;
}

/*
DIBs use RGBQUAD format:
0xbb 0xgg 0xrr 0x00

Reasonably efficient code to convert a COLORREF into an
RGBQUAD is byte-order-dependent, so we need different
code depending on the byte order we're targeting.
*/
#ifndef _MAC
#define RGB_TO_RGBQUAD(r,g,b) (RGB(b,g,r))
#define CLR_TO_RGBQUAD(clr) (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
#else
#define RGB_TO_RGBQUAD(r,g,b) (RGB(r,g,b) << 8)
#define CLR_TO_RGBQUAD(clr) (clr << 8)
#endif

#ifndef _MAC
HBITMAP AFXAPI LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc)
#else
HBITMAP AFXAPI LoadSysColorBitmap(HINSTANCE hInst, HRSRC hRsrc,
HDC hDCGlyphs, BOOL bMonochrome)
#endif
{
struct COLORMAP
{
// use DWORD instead of RGBQUAD so we can compare two RGBQUADs easily
DWORD rgbqFrom;
int iSysColorTo;
};
static const COLORMAP sysColorMap[] =
{
// mapping from color in DIB to system color
{ RGB_TO_RGBQUAD(0x00, 0x00, 0x00), COLOR_BTNTEXT }, // black
{ RGB_TO_RGBQUAD(0x80, 0x80, 0x80), COLOR_BTNSHADOW }, // dark grey
{ RGB_TO_RGBQUAD(0xC0, 0xC0, 0xC0), COLOR_BTNFACE }, // bright grey
{ RGB_TO_RGBQUAD(0xFF, 0xFF, 0xFF), COLOR_BTNHIGHLIGHT } // white
};
const int nMaps = 4;

HGLOBAL hglb;
if ((hglb = ::LoadResource(hInst, hRsrc)) == NULL)
return NULL;

LPBITMAPINFOHEADER lpBitmap = (LPBITMAPINFOHEADER)LockResource(hglb);
if (lpBitmap == NULL)
return NULL;

// make copy of BITMAPINFOHEADER so we can modify the color table
const int nColorTableSize = 16;
UINT nSize = lpBitmap->biSize + nColorTableSize * sizeof(RGBQUAD);
LPBITMAPINFOHEADER lpBitmapInfo = (LPBITMAPINFOHEADER)::malloc(nSize);
if (lpBitmapInfo == NULL)
return NULL;
memcpy(lpBitmapInfo, lpBitmap, nSize);

// color table is in RGBQUAD DIB format
DWORD* pColorTable =
(DWORD*)(((LPBYTE)lpBitmapInfo) + (UINT)lpBitmapInfo->biSize);

for (int iColor = 0; iColor < nColorTableSize; iColor++)
{
// look for matching RGBQUAD color in original
for (int i = 0; i < nMaps; i++)
{
if (pColorTable[iColor] == sysColorMap[i].rgbqFrom)
{
#ifdef _MAC
if (bMonochrome)
{
// all colors except text become white
if (sysColorMap[i].iSysColorTo != COLOR_BTNTEXT)
pColorTable[iColor] = RGB_TO_RGBQUAD(255, 255, 255);
}
else
#endif
pColorTable[iColor] =
CLR_TO_RGBQUAD(::GetSysColor(sysColorMap[i].iSysColorTo));
break;
}
}
}

int nWidth = (int)lpBitmapInfo->biWidth;
int nHeight = (int)lpBitmapInfo->biHeight;
HDC hDCScreen = ::GetDC(NULL);
HBITMAP hbm = ::CreateCompatibleBitmap(hDCScreen, nWidth, nHeight);
::ReleaseDC(NULL, hDCScreen);

if (hbm != NULL)
{
HBITMAP hbmOld = (HBITMAP)::SelectObject(hDCGlyphs, hbm);

LPBYTE lpBits;
lpBits = (LPBYTE)(lpBitmap + 1);
lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);

StretchDIBits(hDCGlyphs, 0, 0, nWidth, nHeight, 0, 0, nWidth, nHeight,
lpBits, (LPBITMAPINFO)lpBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
SelectObject(hDCGlyphs, hbmOld);

#ifdef _MAC
// We don't change this bitmap any more, so get rid of the big,
// wasteful Macintosh port
::SetBitmapReadOnly(hbm, BRO_READONLY);
#endif
}

// free copy of bitmap info struct and resource itself
::free(lpBitmapInfo);
::FreeResource(hglb);

return hbm;
}

#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

CFlatToolbar::CFlatToolbar()
{
m_hbmImageWell = NULL;
m_hInstImageWell = NULL;
m_hRsrcImageWell = NULL;
m_iButtonCapture = -1; // nothing captured

// TONYCL: START: OFFICE97 LOOK AND FEEL
m_nUpButtonIndex = -1;// No previous upstate button
// TONYCL: END: OFFICE97 LOOK AND FEEL

// UISG standard sizes
m_sizeButton.cx = 24;
m_sizeButton.cy = 22;
m_sizeImage.cx = 16;
m_sizeImage.cy = 15;
m_cyTopBorder = m_cyBottomBorder = 3; // 3 pixel for top/bottom gaps

// adjust sizes when running on Win4
if (globalData.bWin4)
{
m_sizeButton.cx = 23;
m_cySharedBorder = m_cxSharedBorder = 0;
m_cxDefaultGap = 8;
}
else
{
m_cxDefaultGap = 6;
m_cySharedBorder = m_cxSharedBorder = 1;
}

#ifdef _MAC
m_hDCGlyphs = CreateCompatibleDC(NULL);
m_hDCMono = ::CreateCompatibleDC(NULL);
if (m_hDCGlyphs == NULL || m_hDCMono == NULL)
AfxThrowResourceException();
#endif

// initialize the toolbar drawing engine
static BOOL bInitialized;
if (!bInitialized)
{
#ifndef _MAC
hDCGlyphs = CreateCompatibleDC(NULL);

// Mono DC and Bitmap for disabled image
hDCMono = ::CreateCompatibleDC(NULL);
#endif

#ifndef _MAC
HBITMAP hbmGray = ::CreateDitherBitmap();
#else
HBITMAP hbmGray = ::CreateDitherBitmap(m_bMonochrome);
#endif
if (hbmGray != NULL)
{
ASSERT(hbrDither == NULL);
hbrDither = ::CreatePatternBrush(hbmGray);
AfxDeleteObject((HGDIOBJ*)&hbmGray);
}

#ifndef _MAC
if (hDCGlyphs == NULL || hDCMono == NULL || hbrDither == NULL)
AfxThrowResourceException();
#else
if (hbrDither == NULL)
AfxThrowResourceException();
#endif
bInitialized = TRUE;
}
}

CFlatToolbar::~CFlatToolbar()
{
#ifdef _MAC
ASSERT(m_hDCGlyphs != NULL);
VERIFY(::DeleteDC(m_hDCGlyphs));

ASSERT(m_hDCMono != NULL);
VERIFY(::DeleteDC(m_hDCMono));
#endif

AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell);
}

BOOL CFlatToolbar::Create(CWnd* pParentWnd, DWORD dwStyle, UINT nID)
{
if (pParentWnd != NULL)
ASSERT_VALID(pParentWnd); // must have a parent

// save the style
m_dwStyle = dwStyle;
if (nID == AFX_IDW_TOOLBAR)
m_dwStyle |= CBRS_HIDE_INPLACE;

// create the HWND
CRect rect;
rect.SetRectEmpty();
LPCTSTR lpszClass = AfxRegisterWndClass(0, ::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)(COLOR_BTNFACE+1), NULL);
if (!CWnd::Create(lpszClass, NULL, dwStyle, rect, pParentWnd, nID))
return FALSE;

// Note: Parent must resize itself for control bar to be resized

return TRUE;
}

void CFlatToolbar::SetSizes(SIZE sizeButton, SIZE sizeImage)
{
ASSERT_VALID(this);
ASSERT(sizeButton.cx > 0 && sizeButton.cy > 0);
ASSERT(sizeImage.cx > 0 && sizeImage.cy > 0);

// button must be big enough to hold image + 3 pixels on each side
ASSERT(sizeButton.cx >= sizeImage.cx + 6);
ASSERT(sizeButton.cy >= sizeImage.cy + 6);

m_sizeButton = sizeButton;
m_sizeImage = sizeImage;

// set height
Invalidate(); // just to be nice if called when toolbar is visible
}

void CFlatToolbar::SetHeight(int cyHeight)
{
ASSERT_VALID(this);

int nHeight = cyHeight;
if (m_dwStyle & CBRS_BORDER_TOP)
cyHeight -= globalData.cyBorder2;
if (m_dwStyle & CBRS_BORDER_BOTTOM)
cyHeight -= globalData.cyBorder2;
m_cyBottomBorder = (cyHeight - m_sizeButton.cy) / 2;
// if there is an extra pixel, m_cyTopBorder will get it
m_cyTopBorder = cyHeight - m_sizeButton.cy - m_cyBottomBorder;
if (m_cyTopBorder < 0)
{
TRACE1("Warning: CFlatToolbar::SetHeight(%d) is smaller than button.\n",
nHeight);
m_cyBottomBorder += m_cyTopBorder;
m_cyTopBorder = 0; // will clip at bottom
}
// bottom border will be ignored (truncate as needed)
Invalidate(); // just to be nice if called when toolbar is visible
}

BOOL CFlatToolbar::LoadBitmap(UINT nIDBitmap)
{
return LoadBitmap(MAKEINTRESOURCE(nIDBitmap));
}

BOOL CFlatToolbar::LoadBitmap(LPCTSTR lpszResourceName)
{
ASSERT_VALID(this);
ASSERT(lpszResourceName != NULL);

AfxDeleteObject((HGDIOBJ*)&m_hbmImageWell); // get rid of old one

m_hInstImageWell = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
if ((m_hRsrcImageWell = ::FindResource(m_hInstImageWell,
lpszResourceName, RT_BITMAP)) == NULL)
return FALSE;

#ifndef _MAC
m_hbmImageWell = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
#else
m_hbmImageWell = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell,
m_hDCGlyphs, m_bMonochrome);
#endif
return (m_hbmImageWell != NULL);
}

BOOL CFlatToolbar::SetButtons(const UINT* lpIDArray, int nIDCount)
{
ASSERT_VALID(this);
ASSERT(nIDCount >= 1); // must be at least one of them
ASSERT(lpIDArray == NULL ||
AfxIsValidAddress(lpIDArray, sizeof(UINT) * nIDCount, FALSE));

// first allocate array for panes and copy initial data
if (!AllocElements(nIDCount, sizeof(AFX_TBBUTTON)))
return FALSE;
ASSERT(nIDCount == m_nCount);

if (lpIDArray != NULL)
{
int iImage = 0;
// go through them adding buttons
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
for (int i = 0; i < nIDCount; i++, pTBB++)
{
ASSERT(pTBB != NULL);
if ((pTBB->nID = *lpIDArray++) == 0)
{
// separator
pTBB->nStyle = TBBS_SEPARATOR;
// width of separator includes 2 pixel overlap
pTBB->iImage = m_cxDefaultGap + m_cxSharedBorder * 2;
}
else
{
// a command button with image
pTBB->nStyle = TBBS_BUTTON;
pTBB->iImage = iImage++;
}
}
}
return TRUE;
}

#ifdef AFX_CORE3_SEG
#pragma code_seg(AFX_CORE3_SEG)
#endif

/////////////////////////////////////////////////////////////////////////////
// CFlatToolbar attribute access

int CFlatToolbar::CommandToIndex(UINT nIDFind) const
{
ASSERT_VALID(this);

AFX_TBBUTTON* pTBB = _GetButtonPtr(0);
for (int i = 0; i < m_nCount; i++, pTBB++)
if (pTBB->nID == nIDFind)
return i;
return -1;
}

UINT CFlatToolbar::GetItemID(int nIndex) const
{
ASSERT_VALID(this);

return _GetButtonPtr(nIndex)->nID;
}

void CFlatToolbar::GetItemRect(int nIndex, LPRECT lpRect) const
{
ASSERT_VALID(this);
ASSERT(nIndex >= 0 && nIndex < m_nCount);
ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));

BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
CRect rect;
rect.SetRectEmpty(); // only need top and left
CalcInsideRect(rect, bHorz);
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
for (int iButton = 0; iButton < nIndex; iButton++, pTBB++)
{
ASSERT(pTBB != NULL);
// skip this button or separator
if (bHorz)
{
rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : m_sizeButton.cx;
rect.left -= m_cxSharedBorder; // go back for overlap
}
else
{
rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : m_sizeButton.cy;
rect.top -= m_cySharedBorder; // go back for overlap
}
}
ASSERT(iButton == nIndex);
ASSERT(pTBB == _GetButtonPtr(nIndex));

// button or image width
if (bHorz)
{
// TONYCL: START: OFFICE97 LOOK AND FEEL
// If we are not floating then shift the buttons down to allow for a gripper
if (!IsFloating()) {
rect.left += 3;
}
// TONYCL: END: OFFICE97 LOOK AND FEEL

int cx = (pTBB->nStyle & TBBS_SEPARATOR) ? pTBB->iImage : m_sizeButton.cx;
lpRect->right = (lpRect->left = rect.left) + cx;
lpRect->bottom = (lpRect->top = rect.top) + m_sizeButton.cy;
}
else
{
// TONYCL: START: OFFICE97 LOOK AND FEEL
// If we are not floating then shift the buttons down to allow for a gripper
if (!IsFloating()) {
rect.top += 3;
}
// TONYCL: END: OFFICE97 LOOK AND FEEL

int cy = (pTBB->nStyle & TBBS_SEPARATOR) ? pTBB->iImage : m_sizeButton.cy;
lpRect->bottom = (lpRect->top = rect.top) + cy;
lpRect->right = (lpRect->left = rect.left) + m_sizeButton.cx;
}
}

UINT CFlatToolbar::GetButtonStyle(int nIndex) const
{
return _GetButtonPtr(nIndex)->nStyle;
}

void CFlatToolbar::SetButtonStyle(int nIndex, UINT nStyle)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
UINT nOldStyle = pTBB->nStyle;
if (nOldStyle != nStyle)
{
// update the style and invalidate
pTBB->nStyle = nStyle;

// invalidate the button only if both styles not "pressed"
if (!(nOldStyle & nStyle & TBBS_PRESSED))
InvalidateButton(nIndex);
}
}

CSize CFlatToolbar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
ASSERT_VALID(this);

CSize size = CControlBar::CalcFixedLayout(bStretch, bHorz);

CRect rect;
rect.SetRectEmpty(); // only need top and left
CalcInsideRect(rect, bHorz);
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
int nButtonDist = 0;

if (!bStretch)
{
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
ASSERT(pTBB != NULL);
// skip this button or separator
nButtonDist += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : (bHorz ? m_sizeButton.cx : m_sizeButton.cy);
// go back one for overlap
nButtonDist -= bHorz ? m_cxSharedBorder : m_cySharedBorder;
}
if (bHorz)
size.cx = nButtonDist - rect.Width() + m_cxSharedBorder;
else
size.cy = nButtonDist - rect.Height() + m_cySharedBorder;
}

if (bHorz)
size.cy = m_sizeButton.cy - rect.Height(); // rect.Height() < 0
else
size.cx = m_sizeButton.cx - rect.Width(); // rect.Width() < 0

return size;
}

void CFlatToolbar::GetButtonInfo(int nIndex, UINT& nID, UINT& nStyle, int& iImage) const
{
ASSERT_VALID(this);

AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
nID = pTBB->nID;
nStyle = pTBB->nStyle;
iImage = pTBB->iImage;
}

void CFlatToolbar::SetButtonInfo(int nIndex, UINT nID, UINT nStyle, int iImage)
{
ASSERT_VALID(this);

AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
pTBB->nID = nID;
pTBB->iImage = iImage;
pTBB->nStyle = nStyle;
InvalidateButton(nIndex);
}

void CFlatToolbar::DoPaint(CDC* pDC)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);

#ifdef _MAC
#ifdef _DEBUG
// turn off validation to speed up button drawing
int wdSav = WlmDebug(WD_NOVALIDATE | WD_ASSERT);
#endif
#endif

CControlBar::DoPaint(pDC);// draw border

// if no toolbar loaded, don't draw any buttons
if (m_hbmImageWell == NULL)
return;

BOOL bHorz = m_dwStyle & CBRS_ORIENT_HORZ ? TRUE : FALSE;
CRect rect;
GetClientRect(rect);
CalcInsideRect(rect, bHorz);

// force the full size of the button
if (bHorz)
rect.bottom = rect.top + m_sizeButton.cy;
else
rect.right = rect.left + m_sizeButton.cx;

DrawState ds;
if (!PrepareDrawButton(ds))
return; // something went wrong

// TONYCL: START: OFFICE97 LOOK AND FEEL
// Only draw the gripper stripes when we are docked
if (!IsFloating()) {
{
CRect rect;
GetClientRect(rect);

// Draw the two gripper stripes
if (bHorz) {
// Adjust the sizes to fit into the client area properly
rect.left += 3;
rect.top += 3;
rect.bottom -= 3;
pDC->Draw3dRect(rect.left, rect.top, 3, rect.Height(), globalData.clrBtnHilite, globalData.clrBtnShadow);

rect.left += 4;
pDC->Draw3dRect(rect.left, rect.top, 3, rect.Height(), globalData.clrBtnHilite, globalData.clrBtnShadow);
}
else {
// Adjust the sizes to fit into the client area properly
rect.top += 3;
rect.left += 3;
rect.right -= 3;
pDC->Draw3dRect(rect.left, rect.top, rect.Width(), 3, globalData.clrBtnHilite, globalData.clrBtnShadow);

rect.top += 4;
pDC->Draw3dRect(rect.left, rect.top, rect.Width(), 3, globalData.clrBtnHilite, globalData.clrBtnShadow);
}
}

// Shift the buttons down by 2 pixels to allow for the grippers
if (bHorz)
rect.left += 3;
else
rect.top += 3;
}

// TONYCL: END: OFFICE97 LOOK AND FEEL

AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
ASSERT(pTBB != NULL);
if (pTBB->nStyle & TBBS_SEPARATOR)
{
// separator
if (bHorz)
rect.right = rect.left + pTBB->iImage;
else
rect.bottom = rect.top + pTBB->iImage;

// TONYCL: START: OFFICE97 LOOK AND FEEL
{
// Draw a 3D seperator
if (bHorz) {

int nOffset; 
nOffset = rect.left + 1 + ((rect.Width() - 2) / 2);
pDC->Draw3dRect(nOffset, rect.top, 2, rect.Height(), globalData.clrBtnShadow, globalData.clrBtnHilite);
}
else {
int nOffset;
nOffset = rect.top + 1 + ((rect.Height() - 2) / 2);
pDC->Draw3dRect(rect.left, nOffset, rect.Width(), 2, globalData.clrBtnShadow, globalData.clrBtnHilite);
}
}
// TONYCL: END: OFFICE97 LOOK AND FEEL
}
else
{
if (bHorz)
rect.right = rect.left + m_sizeButton.cx;
else
rect.bottom = rect.top + m_sizeButton.cy;
if (!globalData.bWin32s || pDC->RectVisible(&rect))
{
DrawButton(pDC, rect.left, rect.top,
pTBB->iImage, pTBB->nStyle);
}
}
// adjust for overlap
if (bHorz)
rect.left = rect.right - m_cxSharedBorder;
else
rect.top = rect.bottom - m_cySharedBorder;
}
EndDrawButton(ds);

#ifdef _MAC
#ifdef _DEBUG
WlmDebug(wdSav);
#endif
#endif
}

void CFlatToolbar::InvalidateButton(int nIndex)
{
ASSERT_VALID(this);

CRect rect;
GetItemRect(nIndex, &rect);
InvalidateRect(rect, FALSE); // don't erase background
}

int CFlatToolbar::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
{
ASSERT_VALID(this);

// check child windows first by calling CControlBar
int nHit = CControlBar::OnToolHitTest(point, pTI);
if (nHit != -1)
return nHit;

// now hit test against CFlatToolbar buttons
nHit = ((CFlatToolbar*)this)->HitTest(point);
if (nHit != -1)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(nHit);
if (pTI != NULL)
{
GetItemRect(nHit, &pTI->rect);
pTI->uId = pTBB->nID;
pTI->hwnd = m_hWnd;
pTI->lpszText = LPSTR_TEXTCALLBACK;
}
nHit = pTBB->nID;
}
return nHit;
}

int CFlatToolbar::HitTest(CPoint point) // in window relative coords
{
if (m_pData == NULL)
return -1;// no buttons

BOOL bHorz = (m_dwStyle & CBRS_ORIENT_HORZ) ? TRUE : FALSE;
CRect rect;
rect.SetRectEmpty(); // only need top and left
CalcInsideRect(rect, bHorz);
AFX_TBBUTTON* pTBB = (AFX_TBBUTTON*)m_pData;
ASSERT(pTBB != NULL);
if (bHorz)
{
if (point.y < rect.top || point.y >= rect.top + m_sizeButton.cy)
return -1; // no Y hit
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
if (point.x < rect.left)
break; // missed it
rect.left += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : m_sizeButton.cx;
if (point.x < rect.left && !(pTBB->nStyle & TBBS_SEPARATOR))
return iButton; // hit !
rect.left -= m_cxSharedBorder; // go back for overlap
}
}
else
{
if (point.x < rect.left || point.x >= rect.left + m_sizeButton.cx)
return -1; // no X hit
for (int iButton = 0; iButton < m_nCount; iButton++, pTBB++)
{
if (point.y < rect.top)
break; // missed it
rect.top += (pTBB->nStyle & TBBS_SEPARATOR) ?
pTBB->iImage : m_sizeButton.cy;
if (point.y < rect.top && !(pTBB->nStyle & TBBS_SEPARATOR))
return iButton; // hit !
rect.top -= m_cySharedBorder; // go back for overlap
}
}

return -1; // nothing hit
}

/////////////////////////////////////////////////////////////////////////////
// CFlatToolbar message handlers

BEGIN_MESSAGE_MAP(CFlatToolbar, CControlBar)
//{{AFX_MSG_MAP(CFlatToolbar)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_CANCELMODE()
ON_WM_SYSCOLORCHANGE()
ON_WM_WINDOWPOSCHANGED()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CFlatToolbar::OnLButtonDown(UINT nFlags, CPoint point)
{
if ((m_iButtonCapture = HitTest(point)) < 0) // nothing hit
{
CControlBar::OnLButtonDown(nFlags, point);
return;
}

AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));

// update the button before checking for disabled status
UpdateButton(m_iButtonCapture);
if (pTBB->nStyle & TBBS_DISABLED)
{
m_iButtonCapture = -1;
return; // don't press it
}

// TONYCL: START:
// Kill the UPSTATE style so that the button is drawn in the downstate
pTBB->nStyle &= ~TBBS_UPSTATE;
// TONYCL: END:

pTBB->nStyle |= TBBS_PRESSED;
InvalidateButton(m_iButtonCapture);
UpdateWindow(); // immediate feedback

SetCapture();
GetOwner()->SendMessage(WM_SETMESSAGESTRING, (WPARAM)pTBB->nID);
}

void CFlatToolbar::OnMouseMove(UINT /*nFlags*/, CPoint point)
{
if (m_iButtonCapture >= 0)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));

UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
int iButtonCapture = m_iButtonCapture;
if (GetCapture() != this)
{
m_iButtonCapture = -1; // lost capture
GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);
}
else
{
// should be pressed if still hitting the captured button
if (HitTest(point) == m_iButtonCapture)
nNewStyle |= TBBS_PRESSED;
}
SetButtonStyle(iButtonCapture, nNewStyle);
UpdateWindow(); // immediate feedback
}
// TONYCL: START: OFFICE97 LOOK AND FEEL
else {
// We have to be the active application
if (GetForegroundWindow()->GetSafeHwnd() == AfxGetMainWnd()->GetSafeHwnd()) {
// Hit test the button, and then draw the button in the up state
int nButtonID = HitTest(point);// Which button are we over?

if (nButtonID == -1) {
ReleaseCapture();
}
else {
SetCapture();
}

// Are we over the same button as we were last time?
if (m_nUpButtonIndex == nButtonID) {
return;
}
// Is the new button -1, and were we over a button?
else if ((nButtonID == -1) && (m_nUpButtonIndex != -1)) {
// Reset the button state so it's flat
UINT nStyle = GetButtonStyle(m_nUpButtonIndex);
nStyle &= ~TBBS_UPSTATE;
SetButtonStyle(m_nUpButtonIndex, nStyle);
InvalidateButton(m_nUpButtonIndex);
m_nUpButtonIndex = -1;
UpdateWindow(); // immediate feedback
}
// We are over a button
else if (nButtonID != -1 && (!(GetButtonStyle(nButtonID) & TBBS_DISABLED))) {
// Put the button into the upstate
UINT nStyle = GetButtonStyle(nButtonID);
nStyle |= TBBS_UPSTATE;
SetButtonStyle(nButtonID, nStyle);
InvalidateButton(nButtonID);

// If we were over a different button to the one before, flatten it
if (m_nUpButtonIndex != -1) {
UINT nStyle = GetButtonStyle(m_nUpButtonIndex);
nStyle &= ~TBBS_UPSTATE;
SetButtonStyle(m_nUpButtonIndex, nStyle);
InvalidateButton(m_nUpButtonIndex);
}

m_nUpButtonIndex = nButtonID;
UpdateWindow(); // immediate feedback
}
}
}
// TONYCL: END: OFFICE97 LOOK AND FEEL
}

void CFlatToolbar::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_iButtonCapture < 0)
{
CControlBar::OnLButtonUp(nFlags, point);
return; // not captured
}

AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
UINT nIDCmd = 0;

UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
if (GetCapture() == this)
{
// we did not lose the capture
ReleaseCapture();
if (HitTest(point) == m_iButtonCapture)
{
// give button a chance to update
UpdateButton(m_iButtonCapture);

// then check for disabled state
if (!(pTBB->nStyle & TBBS_DISABLED))
{
// pressed, will send command notification
nIDCmd = pTBB->nID;

if (pTBB->nStyle & TBBS_CHECKBOX)
{
// auto check: three state => down
if (nNewStyle & TBBS_INDETERMINATE)
nNewStyle &= ~TBBS_INDETERMINATE;

nNewStyle ^= TBBS_CHECKED;
}
}
}
}

GetOwner()->SendMessage(WM_SETMESSAGESTRING, AFX_IDS_IDLEMESSAGE);

int iButtonCapture = m_iButtonCapture;
m_iButtonCapture = -1;
if (nIDCmd != 0)
GetOwner()->SendMessage(WM_COMMAND, nIDCmd); // send command

SetButtonStyle(iButtonCapture, nNewStyle);
UpdateButton(iButtonCapture);

UpdateWindow(); // immediate feedback
}

// TONYCL: START: OFFICE97 LOOK AND FEEL
void CFlatToolbar::OnWindowPosChanged( WINDOWPOS* lpwndpos )
{
// Force a repaint of the window to fix a repaint bug
InvalidateRect(NULL);
UpdateWindow();
}
// TONYCL: END: OFFICE97 LOOK AND FEEL

void CFlatToolbar::OnCancelMode()
{
CControlBar::OnCancelMode();

if (m_iButtonCapture >= 0)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(m_iButtonCapture);
ASSERT(!(pTBB->nStyle & TBBS_SEPARATOR));
UINT nNewStyle = (pTBB->nStyle & ~TBBS_PRESSED);
if (GetCapture() == this)
ReleaseCapture();
SetButtonStyle(m_iButtonCapture, nNewStyle);
m_iButtonCapture = -1;
UpdateWindow();
}
}

void CFlatToolbar::OnSysColorChange()
{
#ifdef _MAC
CControlBar::OnSysColorChange();

ASSERT(hDCGlyphs != NULL);
VERIFY(::DeleteDC(hDCGlyphs));
hDCGlyphs = ::CreateCompatibleDC(NULL);

ASSERT(hDCMono != NULL);
VERIFY(::DeleteDC(hDCMono));
hDCMono = ::CreateCompatibleDC(NULL);
#endif

// re-initialize global dither brush
#ifndef _MAC
HBITMAP hbmGray = ::CreateDitherBitmap();
#else
HBITMAP hbmGray = ::CreateDitherBitmap(m_bMonochrome);
#endif
if (hbmGray != NULL)
{
HBRUSH hbrNew = ::CreatePatternBrush(hbmGray);
if (hbrNew != NULL)
{
AfxDeleteObject((HGDIOBJ*)&hbrDither); // free old one
hbrDither = hbrNew;
}
::DeleteObject(hbmGray);
}

// re-color bitmap for toolbar
if (m_hbmImageWell != NULL)
{
HBITMAP hbmNew;
#ifndef _MAC
hbmNew = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell);
#else
hbmNew = LoadSysColorBitmap(m_hInstImageWell, m_hRsrcImageWell,
m_hDCGlyphs, m_bMonochrome);
#endif
if (hbmNew != NULL)
{
::DeleteObject(m_hbmImageWell); // free old one
m_hbmImageWell = hbmNew;
}
}
}

/////////////////////////////////////////////////////////////////////////////
// CFlatToolbar idle update through CToolCmdUI class

#define CToolCmdUI COldToolCmdUI

class CToolCmdUI : public CCmdUI // class private to this file !
{
public: // re-implementations only
virtual void Enable(BOOL bOn);
virtual void SetCheck(int nCheck);
virtual void SetText(LPCTSTR lpszText);
};

void CToolCmdUI::Enable(BOOL bOn)
{
m_bEnableChanged = TRUE;
CFlatToolbar* pToolBar = (CFlatToolbar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT_KINDOF(CFlatToolbar, pToolBar);
ASSERT(m_nIndex < m_nIndexMax);

UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) & ~TBBS_DISABLED;
if (!bOn)
nNewStyle |= TBBS_DISABLED;
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetButtonStyle(m_nIndex, nNewStyle);
}

void CToolCmdUI::SetCheck(int nCheck)
{
ASSERT(nCheck >= 0 && nCheck <= 2); // 0=>off, 1=>on, 2=>indeterminate
CFlatToolbar* pToolBar = (CFlatToolbar*)m_pOther;
ASSERT(pToolBar != NULL);
ASSERT_KINDOF(CFlatToolbar, pToolBar);
ASSERT(m_nIndex < m_nIndexMax);

UINT nNewStyle = pToolBar->GetButtonStyle(m_nIndex) &
~(TBBS_CHECKED | TBBS_INDETERMINATE);
if (nCheck == 1)
nNewStyle |= TBBS_CHECKED;
else if (nCheck == 2)
nNewStyle |= TBBS_INDETERMINATE;
ASSERT(!(nNewStyle & TBBS_SEPARATOR));
pToolBar->SetButtonStyle(m_nIndex, nNewStyle | TBBS_CHECKBOX);
}

void CToolCmdUI::SetText(LPCTSTR)
{
// ignore it
}

void CFlatToolbar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
CToolCmdUI state;
state.m_pOther = this;

state.m_nIndexMax = (UINT)m_nCount;
for (state.m_nIndex = 0; state.m_nIndex < state.m_nIndexMax;
state.m_nIndex++)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(state.m_nIndex);
state.m_nID = pTBB->nID;

// ignore separators
if (!(pTBB->nStyle & TBBS_SEPARATOR))
state.DoUpdate(pTarget, bDisableIfNoHndler);
}

// update the dialog controls added to the toolbar
UpdateDialogControls(pTarget, bDisableIfNoHndler);
}

void CFlatToolbar::UpdateButton(int nIndex)
{
// determine target of command update
CFrameWnd* pTarget = (CFrameWnd*)GetOwner();
if (pTarget == NULL || !pTarget->IsFrameWnd())
pTarget = GetParentFrame();

// send the update notification
if (pTarget != NULL)
{
CToolCmdUI state;
state.m_pOther = this;
state.m_nIndex = nIndex;
state.m_nIndexMax = (UINT)m_nCount;
AFX_TBBUTTON* pTBB = _GetButtonPtr(nIndex);
state.m_nID = pTBB->nID;
state.DoUpdate(pTarget, pTarget->m_bAutoMenuEnable);
}
}

/////////////////////////////////////////////////////////////////////////////
// CFlatToolbar diagnostics

#ifdef _DEBUG
void CFlatToolbar::AssertValid() const
{
CControlBar::AssertValid();
ASSERT(m_hbmImageWell == NULL ||
(globalData.bWin32s || ::GetObjectType(m_hbmImageWell) == OBJ_BITMAP));

if (m_hbmImageWell != NULL)
{
ASSERT(m_hRsrcImageWell != NULL);
ASSERT(m_hInstImageWell != NULL);
}
}

void CFlatToolbar::Dump(CDumpContext& dc) const
{
CControlBar::Dump(dc);

dc << "m_hbmImageWell = " << (UINT)m_hbmImageWell;
dc << "\nm_hInstImageWell = " << (UINT)m_hInstImageWell;
dc << "\nm_hRsrcImageWell = " << (UINT)m_hRsrcImageWell;
dc << "\nm_iButtonCapture = " << m_iButtonCapture;
dc << "\nm_sizeButton = " << m_sizeButton;
dc << "\nm_sizeImage = " << m_sizeImage;

if (dc.GetDepth() > 0)
{
for (int i = 0; i < m_nCount; i++)
{
AFX_TBBUTTON* pTBB = _GetButtonPtr(i);
dc << "\ntoolbar button[" << i << "] = {";
dc << "\n\tnID = " << pTBB->nID;
dc << "\n\tnStyle = " << pTBB->nStyle;
if (pTBB->nStyle & TBBS_SEPARATOR)
dc << "\n\tiImage (separator width) = " << pTBB->iImage;
else
dc <<"\n\tiImage (bitmap image index) = " << pTBB->iImage;
dc << "\n}";
}
}

dc << "\n";
}
#endif

#undef new
#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

IMPLEMENT_DYNAMIC(CFlatToolbar, CControlBar)

/////////////////////////////////////////////////////////////////////////////
// Cached system metrics, etc

GLOBAL_DATA globalData;

// Initialization code
GLOBAL_DATA::GLOBAL_DATA()
{
// Cache various target platform version information
DWORD dwVersion = ::GetVersion();
nWinVer = (LOBYTE(dwVersion) << 8) + HIBYTE(dwVersion);
bWin32s = (dwVersion & 0x80000000) != 0;
bWin4 = (BYTE)dwVersion >= 4;
bNotWin4 = 1 - bWin4; // for convenience
#ifndef _MAC
bSmCaption = bWin4;
#else
bSmCaption = TRUE;
#endif
bWin31 = bWin32s && !bWin4; // Windows 95 reports Win32s

// Cached system metrics (updated in CWnd::OnWinIniChange)
UpdateSysMetrics();

// Border attributes
hbrLtGray = ::CreateSolidBrush(RGB(192, 192, 192));
hbrDkGray = ::CreateSolidBrush(RGB(128, 128, 128));
ASSERT(hbrLtGray != NULL);
ASSERT(hbrDkGray != NULL);

// Cached system values (updated in CWnd::OnSysColorChange)
hbrBtnFace = NULL;
hbrBtnShadow = NULL;
hbrBtnHilite = NULL;
hbrWindowFrame = NULL;
hpenBtnShadow = NULL;
hpenBtnHilite = NULL;
hpenBtnText = NULL;
UpdateSysColors();

// cxBorder2 and cyBorder are 2x borders for Win4
cxBorder2 = bWin4 ? CX_BORDER*2 : CX_BORDER;
cyBorder2 = bWin4 ? CY_BORDER*2 : CY_BORDER;

// allocated on demand
hStatusFont = NULL;
hToolTipsFont = NULL;
}

// Termination code
GLOBAL_DATA::~GLOBAL_DATA()
{
// cleanup standard brushes
AfxDeleteObject((HGDIOBJ*)&hbrLtGray);
AfxDeleteObject((HGDIOBJ*)&hbrDkGray);
AfxDeleteObject((HGDIOBJ*)&hbrBtnFace);
AfxDeleteObject((HGDIOBJ*)&hbrBtnShadow);
AfxDeleteObject((HGDIOBJ*)&hbrBtnHilite);
AfxDeleteObject((HGDIOBJ*)&hbrWindowFrame);

// cleanup standard pens
AfxDeleteObject((HGDIOBJ*)&hpenBtnShadow);
AfxDeleteObject((HGDIOBJ*)&hpenBtnHilite);
AfxDeleteObject((HGDIOBJ*)&hpenBtnText);

// clean up objects we don't actually create
AfxDeleteObject((HGDIOBJ*)&hStatusFont);
AfxDeleteObject((HGDIOBJ*)&hToolTipsFont);
}

void GLOBAL_DATA::UpdateSysColors()
{
clrBtnFace = ::GetSysColor(COLOR_BTNFACE);
clrBtnShadow = ::GetSysColor(COLOR_BTNSHADOW);
clrBtnHilite = ::GetSysColor(COLOR_BTNHIGHLIGHT);
clrBtnText = ::GetSysColor(COLOR_BTNTEXT);
clrWindowFrame = ::GetSysColor(COLOR_WINDOWFRAME);

AfxDeleteObject((HGDIOBJ*)&hbrBtnFace);
AfxDeleteObject((HGDIOBJ*)&hbrBtnShadow);
AfxDeleteObject((HGDIOBJ*)&hbrBtnHilite);
AfxDeleteObject((HGDIOBJ*)&hbrWindowFrame);

hbrBtnFace = ::CreateSolidBrush(clrBtnFace);
ASSERT(hbrBtnFace != NULL);
hbrBtnShadow = ::CreateSolidBrush(clrBtnShadow);
ASSERT(hbrBtnShadow != NULL);
hbrBtnHilite = ::CreateSolidBrush(clrBtnHilite);
ASSERT(hbrBtnHilite != NULL);
hbrWindowFrame = ::CreateSolidBrush(clrWindowFrame);
ASSERT(hbrWindowFrame != NULL);

AfxDeleteObject((HGDIOBJ*)&hpenBtnShadow);
AfxDeleteObject((HGDIOBJ*)&hpenBtnHilite);
AfxDeleteObject((HGDIOBJ*)&hpenBtnText);

hpenBtnShadow = ::CreatePen(PS_SOLID, 0, clrBtnShadow);
ASSERT(hpenBtnShadow != NULL);
hpenBtnHilite = ::CreatePen(PS_SOLID, 0, clrBtnHilite);
ASSERT(hpenBtnHilite != NULL);
hpenBtnText = ::CreatePen(PS_SOLID, 0, clrBtnText);
ASSERT(hpenBtnText != NULL);
}

void GLOBAL_DATA::UpdateSysMetrics()
{
// Device metrics for screen
HDC hDCScreen = GetDC(NULL);
ASSERT(hDCScreen != NULL);
cxPixelsPerInch = GetDeviceCaps(hDCScreen, LOGPIXELSX);
cyPixelsPerInch = GetDeviceCaps(hDCScreen, LOGPIXELSY);
ReleaseDC(NULL, hDCScreen);
}

/////////////////////////////////////////////////////////////////////////////