FRMTBAR.C

/* 
*frmtbar.c
*
*Implementation of a richedit format bar
*
*/

#include "preinc.h"

#include <windows.h>
#include <windowsx.h>

#include <richedit.h>

#include <commctrl.h>
#include "dbugit.h"

#include "reitp.rh"
#include "frmtbar.h"


ASSERTDATA

/*
*The current format state
*/
typedef struct tagFormatBarState
{
HWNDhwndToolbar;// Toolbar
HWNDhwndName;// Font name combo
HWNDhwndSize;// Font size combo
HWNDhwndColor;// Font color combo

HDChdc;// Our copy of the DC to use
INTcyPerInch;// Pixels per inch vertically

HBRUSHhbrushWindow;// Common brushes
HBRUSHhbrushHighlight;
HBRUSHhbrushButtonFace;
COLORREFcrWindow;// Common colors
COLORREFcrHighlight;
COLORREFcrButtonFace;

CHARFORMATcf;// The current char format
PARAFORMATpf;// The current paragraph format
DWORDdwCFMaskChange;// What changed

LONGrglSize[128];// Possible font sizes
LONGclSize;// Number of font sizes
BOOLfTrueType;// TrueType flag

BOOLfExpectChoice;// Flag that we want next CBN_*
BOOLfGiveUpFocus;// Flag that we are done
} FormatBarState;

#definePfbsGetWindowPtr(_hwnd)\
((FormatBarState *) GetWindowLong(_hwnd, 0))
#defineSetWindowPtr(_hwnd, _p)SetWindowLong(_hwnd, 0, (LONG) _p)

#defineGetFormatBarField(_hwnd, _fld)(PfbsGetWindowPtr(_hwnd)->_fld)

/*
*Range of sizes we'll show user for TrueType fonts
*/
#definelTrueTypeSizeMin4
#definelTrueTypeSizeMac127

static TCHARszFormatBar[] = FORMATBARCLASSNAME;
static TCHARszToolbar[] = TOOLBARCLASSNAME;
static TCHARszComboBox[] = "ComboBox";

/*
*Our own private messages from the combobox edit control to the format bar
*letting up know about important keyevents
*wParam =window ID of the combobox owning the edit control
*lParam =window handle of the combobox owning the edit control
*returns: none
*/
#defineWM_TAB( WM_USER + 1 )
#defineWM_RETURN( WM_USER + 2 )
#defineWM_ESCAPE( WM_USER + 3 )

#definecxDownButton16
#define cxName128 + cxDownButton
#define cxSize40 + cxDownButton
#define cxColor24 + cxDownButton
#definecxGap1(8 + cxName + 8 + cxSize + 8)
#definecxGap2(cxColor + 8)

#defineCFM_MASKS( CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_COLOR )
#defineCFE_EFFECTS( CFE_BOLD | CFE_ITALIC | CFE_UNDERLINE | \
CFE_AUTOCOLOR )

#defineINITIAL_COLOR0x40000000


static TBBUTTON rgtbbutton[] =
{
{ cxGap1, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},

{ tbBold, TBI_Bold, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1},
{ tbItalic, TBI_Italic, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1},
{ tbUnderline, TBI_Underline, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1},
{ cxGap2, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},

{ tbBullet, TBI_Bullet, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1},
{ 0, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},

{ tbDecreaseIndent, TBI_DecreaseIndent, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0L, -1},
{ tbIncreaseIndent, TBI_IncreaseIndent, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0L, -1},
{ 0, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},

{ tbLeft, TBI_Left, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, 0, 0L, -1},
{ tbCenter, TBI_Center, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, 0, 0L, -1},
{ tbRight, TBI_Right, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, 0, 0L, -1},
{ 0, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},
};
#define ctbbutton(sizeof(rgtbbutton) / sizeof(TBBUTTON))

static DWORDrgdwCFEffect[]={ CFE_BOLD, CFE_ITALIC, CFE_UNDERLINE };
static WORDrgwPFAlignment[]={ PFA_LEFT, PFA_CENTER, PFA_RIGHT };

// Hold the old wndproc's !
//$ REVIEW: Make this per instance ?
static WNDPROCpfnEditWndProc = NULL;
static WNDPROCpfnComboBoxWndProc = NULL;
static WNDPROCpfnToolbarWndProc = NULL;

/*
*Color table for dropdown on toolbar. Matches COMMDLG colors
*exactly.
*/
static DWORD rgrgbColors[] = {
RGB( 0, 0, 0), /* Black*/
RGB(128, 0, 0), /* Dark red*/
RGB( 0, 128, 0), /* Dark green*/
RGB(128, 128, 0), /* Dark yellow*/
RGB( 0, 0, 128),/* Dark blue*/
RGB(128, 0, 128),/* Dark purple*/
RGB( 0, 128, 128),/* Dark aqua*/
RGB(128, 128, 128),/* Dark grey*/
RGB(192, 192, 192),/* Light grey*/
RGB(255, 0, 0), /* Light red*/
RGB( 0, 255, 0), /* Light green*/
RGB(255, 255, 0), /* Light yellow */
RGB( 0, 0, 255),/* Light blue*/
RGB(255, 0, 255),/* Light purple */
RGB( 0, 255, 255),/* Light aqua*/
RGB(255, 255, 255),/* White*/
};

const INT crgbColorsMax = sizeof(rgrgbColors) / sizeof(rgrgbColors[0]);

#defineTraceCharFormat(_sz, _pcf)


/*
*UpdateBrush
*
*Purpose:
*Syncs up the brushes with the known color scheme as needed
*
*Arguments:
*hwndHandle of the format bar
*
*Returns:
*None.
*/
LOCAL VOID UpdateBrush(HBRUSH * phbrush, COLORREF * pcr, INT nIndex)
{
COLORREFcr;

if (((cr = GetSysColor(nIndex)) != *pcr) ||
!*phbrush)
{
if (*phbrush)
DeleteObject(*phbrush);
*phbrush = CreateSolidBrush(*pcr = cr);
}
}


/*
*UpdateBrushes
*
*Purpose:
*Syncs up the brushes with the known color scheme as needed
*
*Arguments:
*hwndHandle of the format bar
*
*Returns:
*None.
*/
LOCAL VOID UpdateBrushes(HWND hwnd)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);

UpdateBrush(&pfbs->hbrushWindow, &pfbs->crWindow, COLOR_WINDOW);
UpdateBrush(&pfbs->hbrushHighlight, &pfbs->crHighlight, COLOR_HIGHLIGHT);
UpdateBrush(&pfbs->hbrushButtonFace, &pfbs->crButtonFace, COLOR_BTNFACE);
}


/*
*LFBEditWndProc
*
*Purpose:
*Take care of handling the notifications from the combobox controls we
*get for the format bar
*
*Arguments:
*hwnd
*wMsg
*wParam
*lParam
*
*Returns:
*LRESULT
*/
LRESULT CALLBACK LFBEditWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
LPARAM lParam)
{
switch (wMsg)
{
case WM_KEYDOWN:
{
HWNDhwndCombo = GetParent(hwnd);
HWNDhwndFormatBar = GetParent(GetParent(hwndCombo));
INTnID = GetWindowID(hwndCombo);

switch(wParam)
{

case VK_ESCAPE:
SendMessage(hwndFormatBar, WM_ESCAPE, nID,
(LPARAM) (LPTSTR) hwndCombo);

case VK_TAB:
case VK_RETURN:
return 0;
}
}
break;

case WM_CHAR:
{
HWNDhwndCombo = GetParent(hwnd);
HWNDhwndFormatBar = GetParent(GetParent(hwndCombo));
INTnID = GetWindowID(hwndCombo);

switch(wParam)
{
case VK_RETURN:
SendMessage(hwndFormatBar, WM_RETURN, nID,
(LPARAM) (LPTSTR) hwndCombo);
return 0;

case VK_TAB:
SendMessage(hwndFormatBar, WM_TAB, nID,
(LPARAM) (LPTSTR) hwndCombo);
return 0;

case VK_ESCAPE:
return 0;
}
}
break;

case WM_KEYUP:
switch (wParam)
{
case VK_RETURN:
case VK_TAB:
case VK_ESCAPE:
return 0;
}
break;
}

return CallWindowProc(pfnEditWndProc, hwnd, wMsg, wParam, lParam);
}


/*
*LFBComboBoxWndProc
*
*Purpose:
*Take care of handling the notifications from the combobox controls we
*get for the format bar
*
*Arguments:
*hwnd
*wMsg
*wParam
*lParam
*
*Returns:
*LRESULT
*/
LRESULT CALLBACK LFBComboBoxWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
LPARAM lParam)
{
switch (wMsg)
{
case WM_KEYDOWN:
{
HWNDhwndFormatBar = GetParent(GetParent(hwnd));
INTnID = GetWindowID(hwnd);

switch(wParam)
{
case VK_TAB:
SendMessage(hwndFormatBar, WM_TAB, nID,
(LPARAM) (LPTSTR) hwnd);
return 0;

case VK_RETURN:
SendMessage(hwndFormatBar, WM_RETURN, nID,
(LPARAM) (LPTSTR) hwnd);
return 0;

case VK_ESCAPE:
SendMessage(hwndFormatBar, WM_ESCAPE, nID,
(LPARAM) (LPTSTR) hwnd);
return 0;
}
}
break;

case WM_KEYUP:
case WM_CHAR:
switch(wParam)
{
case VK_TAB:
case VK_RETURN:
case VK_ESCAPE:
return 0;
}
break;
}

return CallWindowProc(pfnComboBoxWndProc, hwnd, wMsg, wParam, lParam);
}


/*
*LFBToolbarWndProc
*
*Purpose:
*Take care of handling the notifications from the combobox controls we
*get for the format bar
*
*Arguments:
*hwnd
*wMsg
*wParam
*lParam
*
*Returns:
*LRESULT
*/

LRESULT CALLBACK LFBToolbarWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
LPARAM lParam)
{
switch (wMsg)
{
case WM_CTLCOLORLISTBOX:
{
FormatBarState *pfbs = PfbsGetWindowPtr(GetParent(hwnd));

// Peek at the current information
UpdateBrush(&pfbs->hbrushButtonFace, &pfbs->crButtonFace,
COLOR_BTNFACE);
return (LRESULT) (LPTSTR) pfbs->hbrushButtonFace;
}
break;
}

return CallWindowProc(pfnToolbarWndProc, hwnd, wMsg, wParam, lParam);
}


/*
*NEnumFontNameProc
*
*Purpose:
*The callback for EnumFontFamilies which fills the font names combobox
*with the available fonts
*
*Arguments:
*
*Returns:
*Non-zero as long a font name can be inserted into the combobox
*/
INT CALLBACK NEnumFontNameProc(LOGFONT * plf, TEXTMETRIC * ptm,
INT nFontType, LPARAM lParam)
{
LRESULT lr;
DWORDdw;

lr = SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) plf->lfFaceName);
if (!(lr == CB_ERR || lr == CB_ERRSPACE))
{
Assert (!(plf->lfCharSet & 0xFFFFFF00));
Assert (!(plf->lfPitchAndFamily & 0xFFFFFF00));
Assert (!(nFontType & 0xFFFF0000));
dw = plf->lfCharSet & 0xFF;
dw <<= 8;
dw |= plf->lfPitchAndFamily & 0xFF;
dw <<= 16;
dw |= nFontType & 0xFFFF;
SendMessage((HWND) lParam, CB_SETITEMDATA, LOWORD(lr), (LPARAM) dw);
}
return !(lr == CB_ERR || lr == CB_ERRSPACE);
}


/*
*FillNames
*
*Purpose:
*Fills the font name combobox with the names of the available fonts
*
*Arguments:
*hwndHandle of the names combobox
*
*Returns:
*None.
*/
LOCAL void FillNames(HWND hwnd)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
HDChdc = pfbs->hdc;
HWNDhwndName = pfbs->hwndName;

// Empty the current list
SendMessage(hwndName, CB_RESETCONTENT, 0, 0);

// Ask for all the font families
EnumFontFamilies((HDC) hdc, (LPTSTR) NULL,
(FONTENUMPROC) NEnumFontNameProc,
(LPARAM) (LPTSTR) hwndName);
}



/*
*FInsertSize
*
*Purpose:
*Inserts a font size entry into the array. Takes care of the necessary
*conversion from logical units to points size. The array is kept in
*ascending order.
*
*Arguments:
*lSizeThe font size in logical units
*pfbsThe current format bar state
*fPointsFlag whether the size is in points or not
*
*Returns:
*TRUE if the font size was successfully added to the array, or was
*present.
*/
BOOL FInsertSize(LONG lSize, FormatBarState * pfbs, BOOL fPoints)
{
LONGclLeft = pfbs->clSize;
LONG *plSize = pfbs->rglSize;

if (clLeft >= sizeof(pfbs->rglSize) / sizeof(LONG))
return FALSE;

// Convert to point sizes
if (!fPoints)
lSize = MulDiv((INT) lSize, 72, pfbs->cyPerInch);

while (clLeft > 0 && *plSize < lSize)
{
++plSize;
--clLeft;
}
if (clLeft && *plSize == lSize)
;
else
{
if (clLeft)
{
MoveMemory(plSize + 1, plSize, clLeft * sizeof(LONG));
}
*plSize = lSize;
++pfbs->clSize;
}
return TRUE;
}


/*
*NEnumFontSizeProc
*
*Purpose:
*The callback for EnumFontFamilies which fills the font names combobox
*with the available fonts
*
*Arguments:
*
*Returns:
*Non-zero as long a font name can be inserted into the combobox
*/
INT CALLBACK NEnumFontSizeProc(LOGFONT * plf, TEXTMETRIC * ptm,
INT nFontType, LPARAM lParam)
{
FormatBarState *pfbs = (FormatBarState *) lParam;

if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
pfbs->fTrueType |= TRUE;
return FInsertSize(ptm->tmHeight - ptm->tmInternalLeading, pfbs, FALSE);
}


/*
*FFillSizes
*
*Purpose:
*Fills the font name combobox with the names of the available fonts
*
*Arguments:
*hwndHandle of the names combobox
*
*Returns:
*TRUE if successful
*/
LOCAL BOOL FFillSizes(HWND hwnd)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
HDChdc = pfbs->hdc;
HWNDhwndSize = pfbs->hwndSize;
TCHAR *pszFaceName = pfbs->cf.szFaceName;
LONGilSize;
LONGlCurrSize;
LONGilMatch;
LONG *plSize = pfbs->rglSize;
TCHARszT[10];
LRESULTlr;
BOOLfSuccess = FALSE;

// Empty the current list
SendMessage(hwndSize, CB_RESETCONTENT, 0, 0);
pfbs->clSize = 0;
pfbs->fTrueType = FALSE;

// Ask for all the font sizes for the given font
EnumFontFamilies((HDC) hdc, pszFaceName,
(FONTENUMPROC) NEnumFontSizeProc, (LPARAM) pfbs);

// If we got a TrueType font, just fill in the array with our sizes
if (pfbs->fTrueType)
{
ilSize = lTrueTypeSizeMin;
while (ilSize < lTrueTypeSizeMac)
*plSize++ = ilSize++;
*plSize = ilSize;
pfbs->clSize = lTrueTypeSizeMac - lTrueTypeSizeMin + 1;
}
// Save ourselves some dereferencing and covert to points
lCurrSize = MulDiv((INT) pfbs->cf.yHeight, 72, 1440);

// Now go through our entries and put them into our listbox
plSize = pfbs->rglSize;
ilMatch = -1;
for (ilSize = 0; ilSize < pfbs->clSize; ++ilSize, ++plSize)
{
wsprintf(szT, "%ld", *plSize);
lr = SendMessage(hwndSize, CB_ADDSTRING, 0, (LPARAM) szT);
AssertSz(!(lr == CB_ERR || lr == CB_ERRSPACE), "Can't add more sizes");
if (lr == CB_ERR || lr == CB_ERRSPACE)
goto CleanUp;

// Try to find out which element will become our current selection
if (*plSize == lCurrSize)
ilMatch = ilSize;
}

// Set our current selection
if (ilMatch >= 0)
SendMessage(hwndSize, CB_SETCURSEL, (WPARAM) ilMatch, 0);
else
{
if (lCurrSize)
wsprintf(szT, "%ld", lCurrSize);
else
szT[0] = 0;
SetWindowText(hwndSize, szT);
}
fSuccess = TRUE;

CleanUp:
return fSuccess;
}


/*
*FillColors
*
*Purpose:
*Fills the font colors combobox with samples of the available colors
*
*Arguments:
*hwndHandle of the names combobox
*
*Returns:
*None.
*/
LOCAL void FillColors(HWND hwnd)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
HWNDhwndColor = pfbs->hwndColor;
INTilMatch = -1;
LRESULTlr;
INTicr;
DWORD *pdw;

// Empty the current list
SendMessage(hwndColor, CB_RESETCONTENT, 0, 0);

for (icr = 0, pdw = rgrgbColors; icr < crgbColorsMax; ++icr, ++pdw)
{
lr = SendMessage(hwndColor, CB_ADDSTRING, 0, (LPARAM) *pdw);
if (lr == CB_ERR || lr == CB_ERRSPACE)
{
TraceError("FillColors: No more room for colors", -1);
break;
}

if (*pdw == pfbs->cf.crTextColor)
ilMatch = icr;
}

SendMessage(hwndColor, CB_SETCURSEL, (WPARAM) ilMatch > 0 ? ilMatch : 0, 0);
}


/*
*FB_OnNcCreate
*
*Purpose:
*We want to draw our own colors for the colors combobox
*
*Arguments:
*hwndThe window
*pmisPointer to a MEASUREITEMSTRUCT to be filled out
*
*Returns:
*None.
*/
LOCAL BOOL FB_OnNcCreate(HWND hwnd, CREATESTRUCT * pcs)
{
RECTrc;
INTcyButton;
INTcyList;
INTyPos;
INTxPos;
HFONThfont;
FormatBarState *pfbs = NULL;
HINSTANCEhinst = pcs->hInstance;
WNDPROC pfnWndProcT;
POINTpt = { 1, 1 };
HWNDhwndT;

// Tell format bar where to find it's state information
pfbs = (FormatBarState *) GlobalAllocPtr(GHND, sizeof(FormatBarState));
if (!pfbs)
goto ErrorNoState;
SetWindowPtr(hwnd, pfbs);
AssertSz(PfbsGetWindowPtr(hwnd) == pfbs, "We didn't write it!");

// Get a few brushes that we'll be using all the time
UpdateBrushes(hwnd);

// Create the toolbar
pfbs->hwndToolbar = CreateToolbarEx(hwnd, CCS_TOP | WS_CHILD,
0, tbFormatBarMax, hinst,
BMP_FormatBar, rgtbbutton, ctbbutton,
16, 16, 16, 16, sizeof(TBBUTTON));

if (!pfbs->hwndToolbar)
goto ErrorNoToolbar;

// Subclass the toolbar
pfnWndProcT = (WNDPROC) SetWindowLong(pfbs->hwndToolbar, GWL_WNDPROC,
(LONG) LFBToolbarWndProc);

// If we don't know what the global ToolbarWndProc is, save it
if (!pfnToolbarWndProc)
pfnToolbarWndProc = pfnWndProcT;

// Determine how tall the buttons are so we can size our other controls
// accordingly
SendMessage(pfbs->hwndToolbar, TB_GETITEMRECT, 1, (LPARAM) &rc);
cyButton = rc.bottom - rc.top + 1;

// Determine how tall the toolbar is so that we can center the comboboxes
GetClientRect(pfbs->hwndToolbar, &rc);
yPos = (rc.bottom - rc.top + 1 - cyButton) / 2 + 1;

// Let's make the comboboxes dropdown about 5 times the height
cyList = 5 * cyButton;

// Get the font to use for the comboboxes
hfont = (HFONT) SendMessage(pfbs->hwndToolbar, WM_GETFONT, 0, 0);

// Now create the other format bar controls

// The name
xPos = 8;
pfbs->hwndName = CreateWindow(szComboBox, NULL,
WS_CHILD | WS_VSCROLL | CBS_DROPDOWN |
CBS_SORT | CBS_HASSTRINGS | WS_VISIBLE,
xPos, yPos, cxName, cyList,
pfbs->hwndToolbar, (HMENU) TBI_Name,
hinst, NULL);
if (!pfbs->hwndName)
goto ErrorNoName;
SetWindowFont(pfbs->hwndName, hfont, TRUE);
xPos += cxName + 8;


// The Size
pfbs->hwndSize = CreateWindow(szComboBox, NULL,
WS_CHILD | WS_VSCROLL | CBS_DROPDOWN |
WS_VISIBLE,
xPos, yPos, cxSize, cyList,
pfbs->hwndToolbar, (HMENU) TBI_Size,
hinst, NULL);
if (!pfbs->hwndSize)
goto ErrorNoSize;
SetWindowFont(pfbs->hwndSize, hfont, TRUE);

// The color
//$ REVIEW: Magic number
SendMessage(pfbs->hwndToolbar, TB_GETITEMRECT, 3, (LPARAM) &rc);
pfbs->hwndColor = CreateWindow(szComboBox, NULL,
WS_CHILD | WS_VSCROLL | CBS_DROPDOWNLIST |
CBS_OWNERDRAWFIXED | WS_VISIBLE,
rc.right, yPos - 1, cxColor, cyList,
pfbs->hwndToolbar, (HMENU) TBI_Color,
hinst, NULL);
if (!pfbs->hwndColor)
goto ErrorNoColor;
SetWindowFont(pfbs->hwndColor, hfont, TRUE);

// Set the initial color to black so it won't be redrawn.
pfbs->cf.dwMask |= INITIAL_COLOR;

// Subclass the comboboxes' edit controls

// Do the name first
hwndT = ChildWindowFromPoint(pfbs->hwndName, pt);
pfnWndProcT = (WNDPROC) SetWindowLong(hwndT, GWL_WNDPROC,
(LONG) LFBEditWndProc);

// If we don't know what the global EditWndProc is, save it
if (!pfnEditWndProc)
pfnEditWndProc = pfnWndProcT;

// Next the size
hwndT = ChildWindowFromPoint(pfbs->hwndSize, pt);
(WNDPROC) SetWindowLong(hwndT, GWL_WNDPROC, (LONG) LFBEditWndProc);

// Lastly the color
pfnWndProcT = (WNDPROC) SetWindowLong(pfbs->hwndColor, GWL_WNDPROC,
(LONG) LFBComboBoxWndProc);

// If we don't know what the global ComboBoxWndProc is, save it
if (!pfnComboBoxWndProc)
pfnComboBoxWndProc = pfnWndProcT;

// Create a copy of the DC that the user gave up to play with
if(pcs->lpCreateParams)
{
HDC *phdc = (HDC *) pcs->lpCreateParams;

pfbs->hdc = CreateCompatibleDC(*phdc);
}
else
{
HDC hdc = GetDC(pcs->hwndParent);

pfbs->hdc = CreateCompatibleDC(hdc);
ReleaseDC(pcs->hwndParent, hdc);
}

if (!pfbs->hdc)
goto ErrorNoColor;

// Get the number of pixels per inch vertically so we can do point sizes
pfbs->cyPerInch = GetDeviceCaps(pfbs->hdc, LOGPIXELSY);

// Load up the names of the fonts and colors
FillNames(hwnd);
FillColors(hwnd);
// Continue creating
return TRUE;

ErrorNoColor:
DestroyWindow(pfbs->hwndSize);
pfbs->hwndSize = NULL;

ErrorNoSize:
DestroyWindow(pfbs->hwndName);
pfbs->hwndName = NULL;

ErrorNoName:
DestroyWindow(pfbs->hwndToolbar);
pfbs->hwndToolbar = NULL;

ErrorNoToolbar:
if (pfbs)
GlobalFreePtr(pfbs);

ErrorNoState:
return FALSE;
}


/*
*FB_OnMeasureItem
*
*Purpose:
*We want to draw our own colors for the colors combobox
*
*Arguments:
*hwndThe window
*pmisPointer to a MEASUREITEMSTRUCT to be filled out
*
*Returns:
*None.
*/
LOCAL void FB_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * pmis)
{
switch (pmis->CtlID)
{
case TBI_Color:
pmis->itemWidth = 128;
pmis->itemHeight = 16;
break;
default:
TraceError("Don't know anything about CtlID", -1);
break;
}
}


/*
*FB_OnDrawItem
*
*Purpose:
*We want to drawn our own colors for our color combobox
*
*Arguments:
*hwndThe window
*pdisPointer to a DRAWITEMSTRUCT to be filled out
*
*Returns:
*None.
*/
LOCAL void FB_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT * pdis)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
HDChdc = pdis->hDC;
RECTrc;
HBRUSHhbrush;
COLORREFcr = (COLORREF) pdis->itemData;
INTnIter = 2;

// As far as we know we have only one owner drawn control
AssertSz(pdis->CtlType == ODT_COMBOBOX, "Know only comboboxes");
if (pdis->CtlID != TBI_Color)
return;

// NULL object wanted ?
if (pdis->itemData == -1)
goto HandleFocus;

switch (pdis->itemAction)
{
case ODA_DRAWENTIRE:
rc = pdis->rcItem;
InflateRect(&rc, -3, -3);
hbrush = CreateSolidBrush((COLORREF)cr);
FillRect(hdc, &rc, hbrush);
DeleteObject(hbrush);
FrameRect(hdc, &rc, GetStockObject(BLACK_BRUSH));

// *** FALL THROUGH ***

case ODA_SELECT:
rc = pdis->rcItem;
if (pdis->itemState & ODS_SELECTED)
hbrush = pfbs->hbrushHighlight;
else
hbrush = pfbs->hbrushWindow;
while (nIter--)
{
InflateRect(&rc, -1, -1);
FrameRect(hdc, &rc, hbrush);
}

if (pdis->itemAction != ODA_DRAWENTIRE)
break;

// *** FALL THROUGH ***

HandleFocus:
case ODA_FOCUS:
if (pdis->itemState & ODS_FOCUS)
hbrush = pfbs->hbrushHighlight;
else
hbrush = pdis->itemData == -1 ? pfbs->hbrushButtonFace :
pfbs->hbrushWindow;
FrameRect(hdc, &pdis->rcItem, hbrush);
break;
}

}


/*
*PaintName
*
*Purpose:
*Paint the current name
*
*Arguments:
*pfbsThe current format bar state
*
*Returns:
*None.
*/
LOCAL VOID PaintName(FormatBarState * pfbs)
{
LONGilFound;

TraceCharFormat("PaintName", &pfbs->cf);
if (pfbs->cf.dwMask & CFM_FACE)
{
ilFound = SendMessage(pfbs->hwndName, CB_FINDSTRING, 0,
(LPARAM) pfbs->cf.szFaceName);
SendMessage(pfbs->hwndName, CB_SETCURSEL, (WPARAM) ilFound, 0);
if (ilFound == CB_ERR)
SetWindowText(pfbs->hwndName, pfbs->cf.szFaceName);
}
else
SetWindowText(pfbs->hwndName, TEXT(""));

}


/*
*PaintSize
*
*Purpose:
*Paint the current size
*
*Arguments:
*pfbsThe current format bar state
*
*Returns:
*None.
*/
LOCAL VOID PaintSize(FormatBarState * pfbs)
{
LONGlSize = MulDiv((INT) pfbs->cf.yHeight, 72, 1440);
LONGilFound;
TCHARszT[10];

TraceCharFormat("PaintSize", &pfbs->cf);
szT[0] = 0;
if (lSize > 0 && (pfbs->cf.dwMask & CFM_SIZE))
wsprintf(szT, "%ld", lSize);
ilFound = SendMessage(pfbs->hwndSize, CB_FINDSTRINGEXACT, 0,
(LPARAM) szT);
SendMessage(pfbs->hwndSize, CB_SETCURSEL, (WPARAM) ilFound, 0);
SetWindowText(pfbs->hwndSize, szT);
}


/*
*PaintColor
*
*Purpose:
*Paint the current color
*
*Arguments:
*pfbsThe current format bar state
*
*Returns:
*None.
*/
LOCAL VOID PaintColor(FormatBarState * pfbs)
{
LONGilFound = -1;
COLORREFcrTextColor = pfbs->cf.crTextColor;

//$ FUTURE: Handle autocolor

// If color isn't known, choose white
TraceCharFormat("PaintColor", &pfbs->cf);
if (pfbs->cf.dwMask & CFM_COLOR)
{
ilFound = SendMessage(pfbs->hwndColor, CB_FINDSTRINGEXACT, 0,
(LPARAM) crTextColor);
if (ilFound < 0)
{
// Not found, add a new color
ilFound = SendMessage(pfbs->hwndColor, CB_ADDSTRING, 0,
(LPARAM) crTextColor);
}
}
SendMessage(pfbs->hwndColor, CB_SETCURSEL, (WPARAM) ilFound, 0);
}


/*
*PaintEffects
*
*Purpose:
*Paint the current effects
*
*Arguments:
*pfbsThe current format bar state
*
*Returns:
*None.
*/
LOCAL VOID PaintEffects(FormatBarState * pfbs)
{
HWNDhwndToolbar = pfbs->hwndToolbar;
DWORDdwMask = pfbs->cf.dwMask;
DWORDdwEffects = pfbs->cf.dwEffects;
BOOLfEffect;
BOOLfMask;
INTnID;

TraceCharFormat("PaintEffects", &pfbs->cf);
for (nID = TBI_Bold; nID <= TBI_Underline; nID++)
{
fMask = dwMask & rgdwCFEffect[nID - TBI_Bold] ? TRUE : FALSE;
fEffect = dwEffects & rgdwCFEffect[nID - TBI_Bold] ? TRUE : FALSE;
#ifdef LIKE_WORD2
// Act like Word
SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(fEffect, 0));
SendMessage(hwndToolbar, TB_INDETERMINATE, nID, MAKELONG(!fMask, 0));
#elif defined(LIKE_T3)
// Act like T3
SendMessage(hwndToolbar, TB_CHECKBUTTON, nID,
MAKELONG(fEffect && fMask, 0));
#else
//$ Raid 2375: Show the user what is actually going to happen
SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(fEffect, 0));
#endif
}

}


/*
*PaintAlignment
*
*Purpose:
*Paint the current alignment
*
*Arguments:
*pfbsThe current format bar state
*
*Returns:
*None.
*/
LOCAL VOID PaintAlignment(FormatBarState * pfbs)
{
HWNDhwndToolbar = pfbs->hwndToolbar;
DWORDwAlignment = pfbs->pf.wAlignment;
INTnID;

if (pfbs->pf.dwMask & PFM_ALIGNMENT)
{
#ifdef LIKE_WORD
// Make all the buttons active
for (nID = TBI_Left; nID <= TBI_Right; nID++)
SendMessage(hwndToolbar, TB_INDETERMINATE, nID,
MAKELONG(FALSE, 0));
#endif
// And press down one of them
switch (wAlignment)
{
case PFA_CENTER:
nID = TBI_Center;
break;

case PFA_RIGHT:
nID = TBI_Right;
break;

case PFA_LEFT:
default:
nID = TBI_Left;
break;
}
SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(TRUE, 0));
}
else
{
#ifdef LIKE_WORD
// Make all the buttons indeterminate
for (nID = TBI_Left; nID <= TBI_Right; nID++)
SendMessage(hwndToolbar, TB_INDETERMINATE, nID, MAKELONG(TRUE, 0));
#else
// Pop all the buttons
for (nID = TBI_Left; nID <= TBI_Right; nID++)
SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(FALSE, 0));
#endif
}
}


/*
*FB_OnCommand
*
*Purpose:
*Handle some of the notifications
*
*Arguments:
*hwndThe window
*pdisPointer to a DRAWITEMSTRUCT to be filled out
*
*Returns:
*None.
*/
LOCAL void FB_OnCommand(HWND hwnd, INT nID, HWND hwndCtl, INT nNotify)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
LONGiSel;
if (nNotify == CBN_ERRSPACE)
{
//$ FUTURE: Handle error out of space
return;
}

switch (nNotify)
{
case CBN_SELENDOK:
// Flag the next combobox message as somethng we want
pfbs->fExpectChoice = TRUE;
pfbs->fGiveUpFocus = TRUE;
return;

case 0:
// This is a button from the toolbar if hwndCtl == pfbs->hwndToolbar
if (hwndCtl != pfbs->hwndToolbar)
return;
break;

case CBN_KILLFOCUS:
switch (nID)
{
case TBI_Name:
PaintName(pfbs);
break;

case TBI_Size:
PaintSize(pfbs);
break;

case TBI_Color:
PaintColor(pfbs);
break;
}
return;

case CBN_SELCHANGE:
// The user is making up his mind so ignore the sel change
if (!pfbs->fExpectChoice)
return;
break;

case CBN_DROPDOWN:
if (nID == TBI_Size)
FFillSizes(hwnd);
return;

//$ REVIEW: Just check for fExpectChoice to shorten this switch ?

// Throw away these notifications from the toolbar
case TBN_BEGINDRAG:
case TBN_ENDDRAG:

// Throw away these notifications from the comboboxes
case CBN_SETFOCUS:
case CBN_CLOSEUP:
case CBN_SELENDCANCEL:
case CBN_EDITCHANGE:
case CBN_EDITUPDATE:
case CBN_DBLCLK:

default:
return;
}

switch (nID)

{ 
case TBI_Name:
if (pfbs->fExpectChoice)
{
DWORDdw;

// Get the new font name
pfbs->cf.dwMask |= CFM_FACE | CFM_CHARSET;
pfbs->dwCFMaskChange = CFM_FACE | CFM_CHARSET;

// Get the new selection
iSel = SendMessage(pfbs->hwndName, CB_GETCURSEL, 0, 0);
if (iSel < 0)
{
//DebugStr("\pBefore GetWindowText in Frmtbar.c");
GetWindowText(pfbs->hwndName, pfbs->cf.szFaceName,
sizeof(pfbs->cf.szFaceName) / sizeof(TCHAR));
pfbs->cf.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
pfbs->cf.bCharSet = DEFAULT_CHARSET;
}
else
{
SendMessage(pfbs->hwndName, CB_GETLBTEXT, (WPARAM) iSel,
(LPARAM) pfbs->cf.szFaceName);

// Pull the other bits of data we had packed away.
dw = ComboBox_GetItemData(pfbs->hwndName, iSel);
dw >>= 16;
pfbs->cf.bPitchAndFamily = (BYTE) dw & 0xFF;
dw >>= 8;
pfbs->cf.bCharSet = (BYTE) dw & 0xFF;
}

// Update the list of font sizes
FFillSizes(hwnd);
pfbs->fExpectChoice = FALSE;
}
break;

case TBI_Size:
if (pfbs->fExpectChoice)
{
TCHARszT[10];
TCHAR *pch = szT;
LONGlSize = 0;

// Get the new font size
pfbs->cf.dwMask |= CFM_SIZE;
pfbs->dwCFMaskChange = CFM_SIZE;
szT[0] = 0;

// Get the new selection
iSel = SendMessage(pfbs->hwndSize, CB_GETCURSEL, 0, 0);
if (iSel < 0)
{
//DebugStr("\pBefore GetWindowText in Format.c2");
GetWindowText(pfbs->hwndSize, szT, sizeof(szT) / sizeof(TCHAR));
}
else
SendMessage(pfbs->hwndSize, CB_GETLBTEXT, (WPARAM) iSel,
(LPARAM) szT);

while (*pch)
{
if (TEXT('0') <= *pch && *pch <= TEXT('9'))
{
lSize *= 10;
lSize += *pch - '0';
}
else
{
// Got a bad character, reject the user's input
lSize = 0;
break;
}
*pch++;
}

if (lSize > 0 && lSize <= yHeightCharPtsMost)
pfbs->cf.yHeight = lSize * 20;// Make twips
else
MessageBox(hwnd, "Size must be between 1 and 1638", "Font",
MB_ICONINFORMATION | MB_OK);
pfbs->fExpectChoice = FALSE;
}
break;

case TBI_Color:
if (pfbs->fExpectChoice)
{
LONG ilSel = SendMessage(pfbs->hwndColor, CB_GETCURSEL, 0, 0);

// Remember that we are picking a color
pfbs->cf.dwMask |= CFM_COLOR;
pfbs->dwCFMaskChange = CFM_COLOR;

//$ FUTURE: For now always turn-off autocolor, but later we'll
//have to handle picking autocolor
pfbs->cf.dwEffects &= ~CFE_AUTOCOLOR;

if (ilSel < 0)
pfbs->cf.crTextColor = 0;
else
pfbs->cf.crTextColor = (COLORREF) SendMessage(pfbs->hwndColor,
CB_GETITEMDATA, (WPARAM) ilSel, 0);
pfbs->fExpectChoice = FALSE;
}
break;

case TBI_Bold:
case TBI_Italic:
case TBI_Underline:

// NOTE: We reverse the if condition because by the time we get the
// notification, the button has already been pressed.
pfbs->dwCFMaskChange = rgdwCFEffect[nID - TBI_Bold];
pfbs->cf.dwMask |= rgdwCFEffect[nID - TBI_Bold];
#ifdef NEVER
if (!SendMessage(pfbs->hwndToolbar, TB_ISBUTTONCHECKED, nID, 0))
pfbs->cf.dwEffects &= ~rgdwCFEffect[nID - TBI_Bold];
else
pfbs->cf.dwEffects |= rgdwCFEffect[nID - TBI_Bold];
#else
pfbs->cf.dwEffects ^= rgdwCFEffect[nID - TBI_Bold];
#endif
pfbs->fGiveUpFocus = TRUE;
break;

case TBI_Bullet:
// NOTE: The button has already been pushed,
// so the checked state is accurate
pfbs->pf.dwMask |= PFM_NUMBERING | PFM_OFFSET;
if (SendMessage(pfbs->hwndToolbar, TB_ISBUTTONCHECKED, nID, 0))
{
pfbs->pf.wNumbering = PFN_BULLET;
pfbs->pf.dxOffset = cxBulletIndent;
}
else
{
pfbs->pf.wNumbering = 0;
pfbs->pf.dxOffset = 0;
}
pfbs->fGiveUpFocus = TRUE;
break;

case TBI_IncreaseIndent:
case TBI_DecreaseIndent:
pfbs->fGiveUpFocus = TRUE;
break;

case TBI_Left:
case TBI_Center:
case TBI_Right:
pfbs->pf.dwMask |= PFM_ALIGNMENT;
pfbs->pf.wAlignment = rgwPFAlignment[nID - TBI_Left];
pfbs->fGiveUpFocus = TRUE;
PaintAlignment(pfbs);
break;



}



// Give up the focus ?
if (pfbs->fGiveUpFocus)
{
pfbs->fGiveUpFocus = FALSE;
SetFocus(hwnd);
}

// Go tell our parent
SendMessage(GetParent(hwnd), WM_COMMAND,
GET_WM_COMMAND_MPS(nID, hwndCtl, nNotify));
}


/*
*FB_OnPaint
*
*Purpose:
*Update our screen
*
*Arguments:
*hwndThe window
*
*Returns:
*None.
*/
LOCAL void FB_OnPaint(HWND hwnd)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
PAINTSTRUCTps;

// Repaint the toolbar as needed
BeginPaint(hwnd, &ps);
//PaintName(pfbs);
//PaintSize(pfbs);
//PaintColor(pfbs);
//PaintEffects(pfbs);
//PaintAlignment(pfbs);
SendMessage(pfbs->hwndToolbar, WM_PAINT, 0, 0);
EndPaint(hwnd, &ps);
}


/*
*SetCharFormat
*
*Purpose:
*Set the current char format
*
*Arguments:
*hwndThe format bar window
*pcfNewThe new formatting
*
*Returns:
*None.
*/
LOCAL VOID SetCharFormat(HWND hwnd, CHARFORMAT *pcfNew)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
CHARFORMAT *pcf = &pfbs->cf;
DWORDdwMask;
DWORDdwEffects;

TraceCharFormat("EM_SETCHARFORMAT", pcfNew);

if(pcfNew->cbSize != sizeof(CHARFORMAT))
return;

// Change in font name ?
if (lstrcmpi(pcf->szFaceName, pcfNew->szFaceName) ||
(pcf->bPitchAndFamily != pcfNew->bPitchAndFamily) ||
(pcf->dwMask & CFM_FACE) != (pcfNew->dwMask & CFM_FACE))
{
pcf->dwMask &= ~CFM_FACE;
pcf->dwMask |= pcfNew->dwMask & CFM_FACE;
lstrcpy(pcf->szFaceName, pcfNew->szFaceName);
pcf->bPitchAndFamily = pcfNew->bPitchAndFamily;
PaintName(pfbs);
}

// Change in charset ?
if (pcf->bCharSet != pcfNew->bCharSet ||
(pcf->dwMask & CFM_CHARSET) != (pcfNew->dwMask & CFM_CHARSET))
{
pcf->dwMask &= ~CFM_CHARSET;
pcf->dwMask |= pcfNew->dwMask & CFM_CHARSET;
pcf->bCharSet = pcfNew->bCharSet;
PaintSize(pfbs);
}

// Change in font size ?
if (pcf->yHeight != pcfNew->yHeight ||
(pcf->dwMask & CFM_SIZE) != (pcfNew->dwMask & CFM_SIZE))
{
pcf->dwMask &= ~CFM_SIZE;
pcf->dwMask |= pcfNew->dwMask & CFM_SIZE;
pcf->yHeight = pcfNew->yHeight;
PaintSize(pfbs);
}

// Change in font color ?
if (pcf->crTextColor != pcfNew->crTextColor ||
(pcf->dwMask & CFM_COLOR) != (pcfNew->dwMask & CFM_COLOR))
{
pcf->dwMask &= ~CFM_COLOR;
pcf->dwMask |= pcfNew->dwMask & CFM_COLOR;
pcf->crTextColor = pcfNew->crTextColor;
PaintColor(pfbs);
}

// Change in effects ?
dwMask = pcf->dwMask & CFM_MASKS;
dwEffects = pcf->dwEffects & CFE_EFFECTS;
if (((pcfNew->dwMask & CFM_MASKS) != dwMask) ||
((pcfNew->dwEffects & CFE_EFFECTS) != dwEffects))
{
pcf->dwMask &= ~CFM_MASKS;
pcf->dwMask |= pcfNew->dwMask & CFM_MASKS;
pcf->dwEffects = pcfNew->dwEffects & CFE_EFFECTS;
PaintEffects(pfbs);
}
}


/*
*SetParaFormat
*
*Purpose:
*Set the current char format
*
*Arguments:
*hwndThe format bar window
*ppfNewThe new formatting
*
*Returns:
*None.
*/
LOCAL VOID SetParaFormat(HWND hwnd, PARAFORMAT *ppfNew)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
PARAFORMAT *ppf = &pfbs->pf;
DWORDdwMaskOld = ppf->dwMask;
BOOLfChanged = FALSE;

// update the mask for tri-state sake
ppf->dwMask = (ppf->dwMask & ~(PFM_NUMBERING | PFM_ALIGNMENT)) |
(ppfNew->dwMask & (PFM_NUMBERING | PFM_ALIGNMENT));

// Change in numbering ?
if (ppf->wNumbering != ppfNew->wNumbering)
{
const BOOL fBulleted = ppfNew->wNumbering == PFN_BULLET;

ppf->wNumbering = ppfNew->wNumbering;
SendMessage(pfbs->hwndToolbar, TB_CHECKBUTTON, TBI_Bullet, MAKELONG(fBulleted, 0));
}

// Change in alignment ?
if (ppf->wAlignment != ppfNew->wAlignment)
{
ppf->wAlignment = ppfNew->wAlignment;
fChanged |= TRUE;
}

if (fChanged || dwMaskOld != ppf->dwMask)
PaintAlignment(pfbs);
}


/*
*LFormatBarWndProc
*
*Purpose:
*Take care of handling the notifications from the combobox controls we
*get from the format bar
*
*Arguments:
*hwnd
*wMsg
*wParam
*lParam
*
*Returns:
*LRESULT
*/
LRESULT CALLBACK LFormatBarWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
LPARAM lParam)
{
FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
BOOL fShift;

switch(wMsg)
{
HANDLE_MSG(hwnd, WM_MEASUREITEM, FB_OnMeasureItem);

case WM_COMMAND:
FB_OnCommand(hwnd, GET_WM_COMMAND_ID(wParam, lParam),
GET_WM_COMMAND_HWND(wParam, lParam),
GET_WM_COMMAND_CMD(wParam, lParam));
return 0;

case WM_NCCREATE:
return FB_OnNcCreate(hwnd, (CREATESTRUCT *) lParam);


case WM_DRAWITEM:
FB_OnDrawItem(hwnd, (DRAWITEMSTRUCT *) lParam);
return TRUE;

case WM_PAINT:
FB_OnPaint(hwnd);
break;

case WM_DESTROY:
if (pfbs)
{
if (pfbs->hwndName)
DestroyWindow(pfbs->hwndName);
if (pfbs->hwndSize)
DestroyWindow(pfbs->hwndSize);
if (pfbs->hwndColor)
DestroyWindow(pfbs->hwndColor);
if (pfbs->hwndToolbar)
DestroyWindow(pfbs->hwndToolbar);
if (pfbs->hbrushWindow)
DeleteObject(pfbs->hbrushWindow);
if (pfbs->hbrushHighlight)
DeleteObject(pfbs->hbrushHighlight);
if (pfbs->hbrushButtonFace)
DeleteObject(pfbs->hbrushButtonFace);
if (pfbs->hdc)
DeleteDC(pfbs->hdc);
GlobalFreePtr(pfbs);
SetWindowPtr(hwnd, NULL);
}
break;

case WM_SHOWWINDOW:
if (pfbs)
{
INTnCmd =wParam ? SW_SHOW : SW_HIDE;

ShowWindow(pfbs->hwndToolbar, nCmd);
SendMessage(pfbs->hwndToolbar, WM_SIZE, 0, 0);
ShowWindow(pfbs->hwndName, nCmd);
ShowWindow(pfbs->hwndSize, nCmd);
ShowWindow(pfbs->hwndColor, nCmd);
}
return 0;

case WM_SIZE:
if (pfbs)
{
RECTrcMe;
RECTrcParent;

// Get our current dimensions
GetClientRect(pfbs->hwndToolbar, &rcMe);
rcMe.bottom += 3;

// We want to fit our parent's width
GetClientRect(GetParent(hwnd), &rcParent);

// Make it so
SetWindowPos(hwnd, HWND_TOP, 0, 0, rcParent.right - rcParent.left,
rcMe.bottom - rcMe.top, SWP_NOMOVE | SWP_NOZORDER);
}
return 0;

case WM_ENABLE:
if (pfbs)
{
INTnID;

EnableWindow(pfbs->hwndToolbar, wParam);
EnableWindow(pfbs->hwndName, wParam);
EnableWindow(pfbs->hwndSize, wParam);
EnableWindow(pfbs->hwndColor, wParam);
for (nID = TBI_Bold; nID <= TBI_Right; nID++)
SendMessage(pfbs->hwndToolbar, TB_ENABLEBUTTON, nID,
MAKELONG(wParam, 0));
}
break;

case WM_SYSCOLORCHANGE:
// Update our concept of the brushes
if (pfbs)
UpdateBrushes(hwnd);
break;

case EM_GETPARAFORMAT:
Assert(lParam);
if (lParam)
{
PARAFORMAT * const ppf = (PARAFORMAT *) lParam;

if(ppf->cbSize == sizeof(PARAFORMAT))
{
CopyMemory(((LPBYTE) ppf) + sizeof(ppf->cbSize),
((LPBYTE) &pfbs->pf) + sizeof(ppf->cbSize),
sizeof(PARAFORMAT) - sizeof(ppf->cbSize));
}
}
return 0;

case EM_SETPARAFORMAT:
Assert(lParam);
if (lParam)
SetParaFormat(hwnd, (PARAFORMAT *) lParam);
return TRUE;

case EM_GETCHARFORMAT:
Assert(lParam);
if (lParam)
{
CHARFORMAT * const pcf = (CHARFORMAT *) lParam;

if(pcf->cbSize == sizeof(CHARFORMAT))
{
CopyMemory(((LPBYTE) pcf) + sizeof(pcf->cbSize),
((LPBYTE) &pfbs->cf) + sizeof(pcf->cbSize),
sizeof(CHARFORMAT) - sizeof(pcf->cbSize));
pcf->dwMask &= pfbs->dwCFMaskChange;
TraceCharFormat("EM_GETCHARFORMAT", pcf);
}
}
return 0;

case EM_SETCHARFORMAT:
Assert(lParam);
if (lParam)
SetCharFormat(hwnd, (CHARFORMAT *) lParam);
return TRUE;

case WM_RETURN:
// The user made a choice
pfbs->fExpectChoice = TRUE;
pfbs->fGiveUpFocus = TRUE;
FB_OnCommand(hwnd, wParam, (HWND) lParam, CBN_SELCHANGE);
return 0;

case WM_TAB:
// Only change the choice if TAB was pressed on a closed dropdown
pfbs->fExpectChoice = !SendMessage((HWND) lParam, CB_GETDROPPEDSTATE,
0, 0);
FB_OnCommand(hwnd, wParam, (HWND) lParam, CBN_SELCHANGE);

// Change focus, FB_OnCommand will take care of copying changed data
fShift = GetKeyState(VK_SHIFT) & 0x8000 ? TRUE : FALSE;
switch (wParam)
{
case TBI_Name:
SetFocus(fShift ? pfbs->hwndColor : pfbs->hwndSize);
break;

case TBI_Size:
SetFocus(fShift ? pfbs->hwndName : pfbs->hwndColor);
break;

case TBI_Color:
SetFocus(fShift ? pfbs->hwndSize : pfbs->hwndName);
break;
}
return 0;

case WM_ESCAPE:
SetFocus(hwnd);
FB_OnPaint(hwnd);
return 0;
}

return DefWindowProc(hwnd, wMsg, wParam, lParam);
}


/*
*FInitFormatBarClass()
*
*Purpose:
*Superclasses the toolbar so that we get support for a format bar
*
*Arguments:
*hinstThis instance
*
*Returns:
*TRUE if class is successfully initialized.
*/
BOOL FInitFormatBarClass(HINSTANCE hinst)
{
WNDCLASS wc;

// Are format bars registered yet ?
if (!GetClassInfo(hinst, szFormatBar, &wc))
{
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = LFormatBarWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(FormatBarState *);
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szFormatBar;

if (!RegisterClass(&wc))
{
TraceError("FInitFormatBarClass: Couldn't register", -1);
return FALSE;
}
}
return TRUE;
}


/*
*FCreateFormatBar
*
*Purpose:
*Creates a format bar
*
*Arguments:
*hwndParentThe parent of this format bar
*wIDThe control ID to be associated with this format bar
*hdcA device context that we can copy so we can do various
*font information functions
*
*Returns:
*The window handle of the format bar
*/
HWND HwndCreateFormatBar(HWND hwndParent, WORD wID, HDC hdc)
{
HWNDhwndFormatBar = NULL;
HINSTANCEhinst = (HINSTANCE) GetWindowLong(hwndParent, GWL_HINSTANCE);
RECTrc;

// Initialize the format bar class
//$ REVIEW: Move into WinMain or LibMain
if (!FInitFormatBarClass(hinst))
{
TraceError("HwndCreateFormatBar: Not registered", -1);
return NULL;
}

// Create the main toolbar
GetClientRect(hwndParent, &rc);
hwndFormatBar = CreateWindow(szFormatBar, NULL, WS_CHILD | WS_VISIBLE,
0, 0, rc.right - rc.left, 29,
hwndParent, (HMENU) wID, hinst,
(LPVOID) (hdc ? &hdc : NULL));
if (!hwndFormatBar)
{
TraceError("HwndCreateFormatBar: Can't create", -1);
goto Error;
}

// Return a pointer to our state information
return hwndFormatBar;

Error:
return NULL;
}