home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / winui / comctl / reitp / frmtbar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-04  |  42.1 KB  |  1,836 lines

  1. /*
  2.  *        frmtbar.c
  3.  *
  4.  *        Implementation of a richedit format bar
  5.  *
  6.  */
  7.  
  8. #include "preinc.h"
  9.  
  10. #include <windows.h>
  11. #include <windowsx.h>
  12.  
  13. #include <richedit.h>
  14.  
  15. #include <commctrl.h>
  16. #include "dbugit.h"
  17.  
  18. #include "reitp.rh"
  19. #include "frmtbar.h"
  20.  
  21.  
  22. ASSERTDATA
  23.  
  24. /*
  25.  *    The current format state
  26.  */
  27. typedef struct tagFormatBarState
  28. {
  29.     HWND            hwndToolbar;                // Toolbar
  30.     HWND            hwndName;                    // Font name combo
  31.     HWND            hwndSize;                    // Font size combo
  32.     HWND            hwndColor;                    // Font color combo
  33.  
  34.     HDC                hdc;                        // Our copy of the DC to use
  35.     INT                cyPerInch;                    // Pixels per inch vertically
  36.  
  37.     HBRUSH            hbrushWindow;                // Common brushes
  38.     HBRUSH            hbrushHighlight;
  39.     HBRUSH            hbrushButtonFace;
  40.     COLORREF        crWindow;                    // Common colors
  41.     COLORREF        crHighlight;
  42.     COLORREF        crButtonFace;
  43.  
  44.     CHARFORMAT        cf;                            // The current char format
  45.     PARAFORMAT        pf;                            // The current paragraph format
  46.     DWORD            dwCFMaskChange;                // What changed
  47.  
  48.     LONG            rglSize[128];                // Possible font sizes
  49.     LONG            clSize;                        // Number of font sizes
  50.     BOOL            fTrueType;                    // TrueType flag
  51.  
  52.     BOOL            fExpectChoice;                // Flag that we want next CBN_*
  53.     BOOL            fGiveUpFocus;                // Flag that we are done
  54. } FormatBarState;
  55.  
  56. #define    PfbsGetWindowPtr(_hwnd)    \
  57.                         ((FormatBarState *) GetWindowLong(_hwnd, 0))
  58. #define    SetWindowPtr(_hwnd, _p)    SetWindowLong(_hwnd, 0, (LONG) _p)
  59.  
  60. #define    GetFormatBarField(_hwnd, _fld)    (PfbsGetWindowPtr(_hwnd)->_fld)
  61.  
  62. /*
  63.  *        Range of sizes we'll show user for TrueType fonts
  64.  */
  65. #define    lTrueTypeSizeMin    4
  66. #define    lTrueTypeSizeMac    127
  67.  
  68. static TCHAR    szFormatBar[] = FORMATBARCLASSNAME;
  69. static TCHAR    szToolbar[] = TOOLBARCLASSNAME;
  70. static TCHAR    szComboBox[] = "ComboBox";
  71.  
  72. /*
  73.  *    Our own private messages from the combobox edit control to the format bar
  74.  *    letting up know about important keyevents
  75.  *        wParam =    window ID of the combobox owning the edit control
  76.  *        lParam =    window handle of the combobox owning the edit control
  77.  *        returns: none
  78.  */
  79. #define    WM_TAB        ( WM_USER + 1 )
  80. #define    WM_RETURN    ( WM_USER + 2 )
  81. #define    WM_ESCAPE    ( WM_USER + 3 )
  82.  
  83. #define    cxDownButton    16
  84. #define cxName            128 + cxDownButton
  85. #define cxSize            40 + cxDownButton
  86. #define cxColor            24 + cxDownButton
  87. #define    cxGap1            (8 + cxName + 8 + cxSize + 8)
  88. #define    cxGap2            (cxColor + 8)
  89.  
  90. #define    CFM_MASKS        ( CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_COLOR )
  91. #define    CFE_EFFECTS        ( CFE_BOLD | CFE_ITALIC | CFE_UNDERLINE | \
  92.                             CFE_AUTOCOLOR )
  93.  
  94. #define    INITIAL_COLOR        0x40000000
  95.  
  96.  
  97. static TBBUTTON rgtbbutton[] =
  98. {
  99.     { cxGap1, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},
  100.  
  101.     { tbBold, TBI_Bold, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1},
  102.     { tbItalic, TBI_Italic, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1}, 
  103.     { tbUnderline, TBI_Underline, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1}, 
  104.     { cxGap2, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},
  105.  
  106.     { tbBullet, TBI_Bullet, TBSTATE_ENABLED, TBSTYLE_CHECK, 0, 0, 0L, -1},
  107.     { 0, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},
  108.  
  109.     { tbDecreaseIndent, TBI_DecreaseIndent, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0L, -1},
  110.     { tbIncreaseIndent, TBI_IncreaseIndent, TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0, 0L, -1},
  111.     { 0, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},
  112.  
  113.     { tbLeft, TBI_Left, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, 0, 0L, -1},
  114.     { tbCenter, TBI_Center, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, 0, 0L, -1}, 
  115.     { tbRight, TBI_Right, TBSTATE_ENABLED, TBSTYLE_CHECKGROUP, 0, 0, 0L, -1}, 
  116.     { 0, 0L, TBSTATE_ENABLED, TBSTYLE_SEP, 0, 0, 0L, -1},
  117. };
  118. #define ctbbutton    (sizeof(rgtbbutton) / sizeof(TBBUTTON))
  119.  
  120. static DWORD    rgdwCFEffect[]    =    { CFE_BOLD, CFE_ITALIC, CFE_UNDERLINE };
  121. static WORD        rgwPFAlignment[]    =    { PFA_LEFT, PFA_CENTER, PFA_RIGHT };
  122.  
  123. // Hold the old wndproc's !
  124. //$ REVIEW: Make this per instance ?
  125. static WNDPROC    pfnEditWndProc = NULL;
  126. static WNDPROC    pfnComboBoxWndProc = NULL;
  127. static WNDPROC    pfnToolbarWndProc = NULL;
  128.  
  129. /*
  130.  *    Color table for dropdown on toolbar.  Matches COMMDLG colors
  131.  *    exactly.
  132.  */
  133. static DWORD rgrgbColors[] = {
  134.     RGB(  0,   0, 0),      /* Black    */
  135.     RGB(128,   0, 0),      /* Dark red    */
  136.     RGB(  0, 128, 0),      /* Dark green    */
  137.     RGB(128, 128, 0),      /* Dark yellow    */
  138.     RGB(  0,   0, 128),    /* Dark blue    */
  139.     RGB(128,   0, 128),    /* Dark purple    */
  140.     RGB(  0, 128, 128),    /* Dark aqua    */
  141.     RGB(128, 128, 128),    /* Dark grey    */
  142.     RGB(192, 192, 192),    /* Light grey    */
  143.     RGB(255,   0, 0),      /* Light red    */
  144.     RGB(  0, 255, 0),      /* Light green    */
  145.     RGB(255, 255, 0),      /* Light yellow */
  146.     RGB(  0,   0, 255),    /* Light blue    */
  147.     RGB(255,   0, 255),    /* Light purple */
  148.     RGB(  0, 255, 255),    /* Light aqua    */
  149.     RGB(255, 255, 255),    /* White    */
  150. };
  151.  
  152. const INT crgbColorsMax = sizeof(rgrgbColors) / sizeof(rgrgbColors[0]);
  153.  
  154. #define    TraceCharFormat(_sz, _pcf)
  155.  
  156.  
  157. /*
  158.  *    UpdateBrush
  159.  *
  160.  *    Purpose:
  161.  *        Syncs up the brushes with the known color scheme as needed
  162.  *
  163.  *    Arguments:
  164.  *        hwnd        Handle of the format bar
  165.  *
  166.  *    Returns:
  167.  *        None.
  168.  */
  169. LOCAL VOID UpdateBrush(HBRUSH * phbrush, COLORREF * pcr, INT nIndex)
  170. {
  171.     COLORREF            cr;
  172.  
  173.     if (((cr = GetSysColor(nIndex)) != *pcr) ||
  174.         !*phbrush)
  175.     {
  176.         if (*phbrush)
  177.             DeleteObject(*phbrush);
  178.         *phbrush = CreateSolidBrush(*pcr = cr);
  179.     }
  180. }
  181.  
  182.  
  183. /*
  184.  *    UpdateBrushes
  185.  *
  186.  *    Purpose:
  187.  *        Syncs up the brushes with the known color scheme as needed
  188.  *
  189.  *    Arguments:
  190.  *        hwnd        Handle of the format bar
  191.  *
  192.  *    Returns:
  193.  *        None.
  194.  */
  195. LOCAL VOID UpdateBrushes(HWND hwnd)
  196. {
  197.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  198.  
  199.     UpdateBrush(&pfbs->hbrushWindow, &pfbs->crWindow, COLOR_WINDOW);
  200.     UpdateBrush(&pfbs->hbrushHighlight, &pfbs->crHighlight, COLOR_HIGHLIGHT);
  201.     UpdateBrush(&pfbs->hbrushButtonFace, &pfbs->crButtonFace, COLOR_BTNFACE);
  202. }
  203.  
  204.  
  205. /*
  206.  *    LFBEditWndProc
  207.  *
  208.  *    Purpose:
  209.  *        Take care of handling the notifications from the combobox controls we
  210.  *        get for the format bar
  211.  *
  212.  *    Arguments:
  213.  *        hwnd
  214.  *        wMsg
  215.  *        wParam
  216.  *        lParam
  217.  *
  218.  *    Returns:
  219.  *        LRESULT
  220.  */
  221. LRESULT CALLBACK LFBEditWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
  222.                                     LPARAM lParam)
  223. {
  224.     switch (wMsg)
  225.     {
  226.     case WM_KEYDOWN:
  227.         {
  228.             HWND    hwndCombo = GetParent(hwnd);
  229.             HWND    hwndFormatBar = GetParent(GetParent(hwndCombo));
  230.             INT        nID = GetWindowID(hwndCombo);
  231.  
  232.             switch(wParam)
  233.             {
  234.  
  235.             case VK_ESCAPE:
  236.                 SendMessage(hwndFormatBar, WM_ESCAPE, nID,
  237.                             (LPARAM) (LPTSTR) hwndCombo);
  238.  
  239.             case VK_TAB:
  240.             case VK_RETURN:
  241.                 return 0;
  242.             }
  243.         }
  244.         break;
  245.  
  246.     case WM_CHAR:
  247.         {
  248.             HWND    hwndCombo = GetParent(hwnd);
  249.             HWND    hwndFormatBar = GetParent(GetParent(hwndCombo));
  250.             INT        nID = GetWindowID(hwndCombo);
  251.  
  252.             switch(wParam)
  253.             {
  254.             case VK_RETURN:
  255.                 SendMessage(hwndFormatBar, WM_RETURN, nID,
  256.                             (LPARAM) (LPTSTR) hwndCombo);
  257.                 return 0;
  258.  
  259.             case VK_TAB:
  260.                 SendMessage(hwndFormatBar, WM_TAB, nID,
  261.                             (LPARAM) (LPTSTR) hwndCombo);
  262.                 return 0;
  263.  
  264.                case VK_ESCAPE:
  265.                 return 0;
  266.             }
  267.         }
  268.         break;
  269.  
  270.     case WM_KEYUP:
  271.         switch (wParam)
  272.         {
  273.         case VK_RETURN:
  274.         case VK_TAB:
  275.         case VK_ESCAPE:
  276.             return 0;
  277.         }
  278.         break;
  279.     }
  280.  
  281.     return CallWindowProc(pfnEditWndProc, hwnd, wMsg, wParam, lParam);
  282. }
  283.  
  284.  
  285. /*
  286.  *    LFBComboBoxWndProc
  287.  *
  288.  *    Purpose:
  289.  *        Take care of handling the notifications from the combobox controls we
  290.  *        get for the format bar
  291.  *
  292.  *    Arguments:
  293.  *        hwnd
  294.  *        wMsg
  295.  *        wParam
  296.  *        lParam
  297.  *
  298.  *    Returns:
  299.  *        LRESULT
  300.  */
  301. LRESULT CALLBACK LFBComboBoxWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
  302.                                     LPARAM lParam)
  303. {
  304.     switch (wMsg)
  305.     {
  306.     case WM_KEYDOWN:
  307.         {
  308.             HWND    hwndFormatBar = GetParent(GetParent(hwnd));
  309.             INT        nID = GetWindowID(hwnd);
  310.  
  311.             switch(wParam)
  312.             {
  313.             case VK_TAB:
  314.                 SendMessage(hwndFormatBar, WM_TAB, nID,
  315.                             (LPARAM) (LPTSTR) hwnd);
  316.                 return 0;
  317.  
  318.             case VK_RETURN:
  319.                 SendMessage(hwndFormatBar, WM_RETURN, nID,
  320.                             (LPARAM) (LPTSTR) hwnd);
  321.                 return 0;
  322.  
  323.             case VK_ESCAPE:
  324.                 SendMessage(hwndFormatBar, WM_ESCAPE, nID,
  325.                             (LPARAM) (LPTSTR) hwnd);
  326.                 return 0;
  327.             }
  328.         }
  329.         break;
  330.  
  331.     case WM_KEYUP:
  332.     case WM_CHAR:
  333.         switch(wParam)
  334.         {
  335.             case VK_TAB:
  336.             case VK_RETURN:
  337.             case VK_ESCAPE:
  338.                 return 0;
  339.         }
  340.         break;
  341.     }
  342.  
  343.     return CallWindowProc(pfnComboBoxWndProc, hwnd, wMsg, wParam, lParam);
  344. }
  345.  
  346.  
  347. /*
  348.  *    LFBToolbarWndProc
  349.  *
  350.  *    Purpose:
  351.  *        Take care of handling the notifications from the combobox controls we
  352.  *        get for the format bar
  353.  *
  354.  *    Arguments:
  355.  *        hwnd
  356.  *        wMsg
  357.  *        wParam
  358.  *        lParam
  359.  *
  360.  *    Returns:
  361.  *        LRESULT
  362.  */
  363.  
  364. LRESULT CALLBACK LFBToolbarWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
  365.                                     LPARAM lParam)
  366. {
  367.     switch (wMsg)
  368.     {
  369.     case WM_CTLCOLORLISTBOX:
  370.             {
  371.                 FormatBarState *    pfbs = PfbsGetWindowPtr(GetParent(hwnd));
  372.  
  373.                 // Peek at the current information
  374.                 UpdateBrush(&pfbs->hbrushButtonFace, &pfbs->crButtonFace,
  375.                             COLOR_BTNFACE);
  376.                 return (LRESULT) (LPTSTR) pfbs->hbrushButtonFace;
  377.             }
  378.         break;
  379.     }
  380.  
  381.     return CallWindowProc(pfnToolbarWndProc, hwnd, wMsg, wParam, lParam);
  382. }
  383.  
  384.  
  385. /*
  386.  *    NEnumFontNameProc
  387.  *
  388.  *    Purpose:
  389.  *        The callback for EnumFontFamilies which fills the font names combobox
  390.  *        with the available fonts
  391.  *
  392.  *    Arguments:
  393.  *
  394.  *    Returns:
  395.  *        Non-zero as long a font name can be inserted into the combobox
  396.  */
  397. INT CALLBACK NEnumFontNameProc(LOGFONT * plf, TEXTMETRIC * ptm,
  398.                                 INT nFontType, LPARAM lParam)
  399. {
  400.     LRESULT lr;
  401.     DWORD    dw;
  402.  
  403.     lr = SendMessage((HWND) lParam, CB_ADDSTRING, 0, (LPARAM) plf->lfFaceName);
  404.     if (!(lr == CB_ERR || lr == CB_ERRSPACE))
  405.     {
  406.         Assert (!(plf->lfCharSet & 0xFFFFFF00));
  407.         Assert (!(plf->lfPitchAndFamily & 0xFFFFFF00));
  408.         Assert (!(nFontType & 0xFFFF0000));
  409.         dw = plf->lfCharSet & 0xFF;
  410.         dw <<= 8;
  411.         dw |= plf->lfPitchAndFamily & 0xFF;
  412.         dw <<= 16;
  413.         dw |= nFontType & 0xFFFF;
  414.         SendMessage((HWND) lParam, CB_SETITEMDATA, LOWORD(lr), (LPARAM) dw);
  415.     }
  416.     return !(lr == CB_ERR || lr == CB_ERRSPACE);
  417. }
  418.  
  419.  
  420. /*
  421.  *    FillNames
  422.  *
  423.  *    Purpose:
  424.  *        Fills the font name combobox with the names of the available fonts
  425.  *
  426.  *    Arguments:
  427.  *        hwnd            Handle of the names combobox
  428.  *
  429.  *    Returns:
  430.  *        None.
  431.  */
  432. LOCAL void FillNames(HWND hwnd)
  433. {
  434.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  435.     HDC                    hdc = pfbs->hdc;
  436.     HWND                hwndName = pfbs->hwndName;
  437.  
  438.     // Empty the current list
  439.     SendMessage(hwndName, CB_RESETCONTENT, 0, 0);
  440.  
  441.     // Ask for all the font families
  442.     EnumFontFamilies((HDC) hdc, (LPTSTR) NULL,
  443.                      (FONTENUMPROC) NEnumFontNameProc,
  444.                      (LPARAM) (LPTSTR) hwndName);
  445. }
  446.  
  447.  
  448.  
  449. /*
  450.  *    FInsertSize
  451.  *
  452.  *    Purpose:
  453.  *        Inserts a font size entry into the array. Takes care of the necessary
  454.  *        conversion from logical units to points size. The array is kept in
  455.  *        ascending order.
  456.  *
  457.  *    Arguments:
  458.  *        lSize            The font size in logical units
  459.  *        pfbs            The current format bar state
  460.  *        fPoints            Flag whether the size is in points or not
  461.  *
  462.  *    Returns:
  463.  *        TRUE if the font size was successfully added to the array, or was
  464.  *        present.
  465.  */
  466. BOOL FInsertSize(LONG lSize, FormatBarState * pfbs, BOOL fPoints)
  467. {
  468.     LONG    clLeft = pfbs->clSize;
  469.     LONG *    plSize = pfbs->rglSize;
  470.  
  471.     if (clLeft >= sizeof(pfbs->rglSize) / sizeof(LONG))
  472.         return FALSE;
  473.  
  474.     // Convert to point sizes
  475.     if (!fPoints)
  476.         lSize = MulDiv((INT) lSize, 72, pfbs->cyPerInch);
  477.  
  478.     while (clLeft > 0 && *plSize < lSize)
  479.     {
  480.         ++plSize;
  481.         --clLeft;
  482.     }
  483.     if (clLeft && *plSize == lSize)
  484.         ;
  485.     else
  486.     {
  487.         if (clLeft)
  488.         {
  489.             MoveMemory(plSize + 1, plSize, clLeft * sizeof(LONG));
  490.         }
  491.         *plSize = lSize;
  492.         ++pfbs->clSize;
  493.     }
  494.     return TRUE;
  495. }
  496.  
  497.  
  498. /*
  499.  *    NEnumFontSizeProc
  500.  *
  501.  *    Purpose:
  502.  *        The callback for EnumFontFamilies which fills the font names combobox
  503.  *        with the available fonts
  504.  *
  505.  *    Arguments:
  506.  *
  507.  *    Returns:
  508.  *        Non-zero as long a font name can be inserted into the combobox
  509.  */
  510. INT CALLBACK NEnumFontSizeProc(LOGFONT * plf, TEXTMETRIC * ptm,
  511.                                 INT nFontType, LPARAM lParam)
  512. {
  513.     FormatBarState *    pfbs = (FormatBarState *) lParam;
  514.  
  515.     if (ptm->tmPitchAndFamily & TMPF_TRUETYPE)
  516.         pfbs->fTrueType |= TRUE;
  517.     return FInsertSize(ptm->tmHeight - ptm->tmInternalLeading, pfbs, FALSE);
  518. }
  519.  
  520.  
  521. /*
  522.  *    FFillSizes
  523.  *
  524.  *    Purpose:
  525.  *        Fills the font name combobox with the names of the available fonts
  526.  *
  527.  *    Arguments:
  528.  *        hwnd            Handle of the names combobox
  529.  *
  530.  *    Returns:
  531.  *        TRUE if successful
  532.  */
  533. LOCAL BOOL FFillSizes(HWND hwnd)
  534. {
  535.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  536.     HDC                    hdc = pfbs->hdc;
  537.     HWND                hwndSize = pfbs->hwndSize;
  538.     TCHAR *                pszFaceName = pfbs->cf.szFaceName;
  539.     LONG                ilSize;
  540.     LONG                lCurrSize;
  541.     LONG                ilMatch;
  542.     LONG *                plSize  = pfbs->rglSize;
  543.     TCHAR                szT[10];
  544.     LRESULT                lr;
  545.     BOOL                fSuccess = FALSE;
  546.  
  547.     // Empty the current list
  548.     SendMessage(hwndSize, CB_RESETCONTENT, 0, 0);
  549.     pfbs->clSize = 0;
  550.     pfbs->fTrueType = FALSE;
  551.  
  552.     // Ask for all the font sizes for the given font
  553.     EnumFontFamilies((HDC) hdc, pszFaceName,
  554.                      (FONTENUMPROC) NEnumFontSizeProc, (LPARAM) pfbs);
  555.  
  556. // If we got a TrueType font, just fill in the array with our sizes
  557.     if (pfbs->fTrueType)
  558.     {
  559.         ilSize = lTrueTypeSizeMin;
  560.         while (ilSize < lTrueTypeSizeMac)
  561.             *plSize++ = ilSize++;
  562.         *plSize = ilSize;
  563.         pfbs->clSize = lTrueTypeSizeMac - lTrueTypeSizeMin + 1;
  564.     }
  565.     // Save ourselves some dereferencing and covert to points
  566.     lCurrSize = MulDiv((INT) pfbs->cf.yHeight, 72, 1440);
  567.  
  568.     // Now go through our entries and put them into our listbox
  569.     plSize  = pfbs->rglSize;
  570.     ilMatch = -1;
  571.     for (ilSize = 0; ilSize < pfbs->clSize; ++ilSize, ++plSize)
  572.     {
  573.         wsprintf(szT, "%ld", *plSize);
  574.         lr = SendMessage(hwndSize, CB_ADDSTRING, 0, (LPARAM) szT);
  575.         AssertSz(!(lr == CB_ERR || lr == CB_ERRSPACE), "Can't add more sizes");
  576.         if (lr == CB_ERR || lr == CB_ERRSPACE)
  577.             goto CleanUp;
  578.  
  579.         // Try to find out which element will become our current selection
  580.         if (*plSize == lCurrSize)
  581.             ilMatch = ilSize;
  582.     }
  583.  
  584.     // Set our current selection
  585.     if (ilMatch >= 0)
  586.         SendMessage(hwndSize, CB_SETCURSEL, (WPARAM) ilMatch, 0);
  587.     else
  588.     {
  589.         if (lCurrSize)
  590.             wsprintf(szT, "%ld", lCurrSize);
  591.         else
  592.             szT[0] = 0;
  593.         SetWindowText(hwndSize, szT);
  594.     }
  595.     fSuccess = TRUE;
  596.  
  597. CleanUp:
  598.     return fSuccess;
  599. }
  600.  
  601.  
  602. /*
  603.  *    FillColors
  604.  *
  605.  *    Purpose:
  606.  *        Fills the font colors combobox with samples of the available colors
  607.  *
  608.  *    Arguments:
  609.  *        hwnd            Handle of the names combobox
  610.  *
  611.  *    Returns:
  612.  *        None.
  613.  */
  614. LOCAL void FillColors(HWND hwnd)
  615. {
  616.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  617.     HWND                hwndColor = pfbs->hwndColor;
  618.     INT                    ilMatch = -1;
  619.     LRESULT                lr;
  620.     INT                    icr;
  621.     DWORD *                pdw;
  622.  
  623.     // Empty the current list
  624.     SendMessage(hwndColor, CB_RESETCONTENT, 0, 0);
  625.  
  626.     for (icr = 0, pdw = rgrgbColors; icr < crgbColorsMax; ++icr, ++pdw)
  627.     {
  628.         lr = SendMessage(hwndColor, CB_ADDSTRING, 0, (LPARAM) *pdw);
  629.         if (lr == CB_ERR || lr == CB_ERRSPACE)
  630.         {
  631.             TraceError("FillColors: No more room for colors", -1);
  632.             break;
  633.         }
  634.  
  635.         if (*pdw == pfbs->cf.crTextColor)
  636.             ilMatch = icr;
  637.     }
  638.  
  639.     SendMessage(hwndColor, CB_SETCURSEL, (WPARAM) ilMatch > 0 ? ilMatch : 0, 0);
  640. }
  641.  
  642.  
  643. /*
  644.  *    FB_OnNcCreate
  645.  *
  646.  *    Purpose:
  647.  *        We want to draw our own colors for the colors combobox
  648.  *
  649.  *    Arguments:
  650.  *        hwnd        The window
  651.  *        pmis        Pointer to a MEASUREITEMSTRUCT to be filled out
  652.  *
  653.  *    Returns:
  654.  *        None.
  655.  */
  656. LOCAL BOOL FB_OnNcCreate(HWND hwnd, CREATESTRUCT * pcs)
  657. {
  658.     RECT                rc;
  659.     INT                    cyButton;
  660.     INT                    cyList;
  661.     INT                    yPos;
  662.     INT                    xPos;
  663.     HFONT                hfont;
  664.     FormatBarState *    pfbs = NULL;
  665.     HINSTANCE            hinst = pcs->hInstance;
  666.     WNDPROC             pfnWndProcT;
  667.     POINT                pt = { 1, 1 };
  668.     HWND                hwndT;
  669.  
  670.     // Tell format bar where to find it's state information
  671.     pfbs = (FormatBarState *) GlobalAllocPtr(GHND, sizeof(FormatBarState));
  672.     if (!pfbs)
  673.         goto ErrorNoState;
  674.     SetWindowPtr(hwnd, pfbs);
  675.     AssertSz(PfbsGetWindowPtr(hwnd) == pfbs, "We didn't write it!");
  676.  
  677.     // Get a few brushes that we'll be using all the time
  678.     UpdateBrushes(hwnd);
  679.  
  680.     // Create the toolbar
  681.     pfbs->hwndToolbar = CreateToolbarEx(hwnd, CCS_TOP | WS_CHILD,
  682.                                         0, tbFormatBarMax, hinst,
  683.                                         BMP_FormatBar, rgtbbutton, ctbbutton,
  684.                                         16, 16, 16, 16, sizeof(TBBUTTON));
  685.  
  686.     if (!pfbs->hwndToolbar)
  687.         goto ErrorNoToolbar;
  688.  
  689.     // Subclass the toolbar
  690.     pfnWndProcT = (WNDPROC) SetWindowLong(pfbs->hwndToolbar, GWL_WNDPROC,
  691.                                                 (LONG) LFBToolbarWndProc);
  692.  
  693.     // If we don't know what the global ToolbarWndProc is, save it
  694.     if (!pfnToolbarWndProc)
  695.         pfnToolbarWndProc = pfnWndProcT;
  696.     
  697.     // Determine how tall the buttons are so we can size our other controls
  698.     // accordingly
  699.     SendMessage(pfbs->hwndToolbar, TB_GETITEMRECT, 1, (LPARAM) &rc);
  700.     cyButton = rc.bottom - rc.top + 1;
  701.  
  702.     // Determine how tall the toolbar is so that we can center the comboboxes
  703.     GetClientRect(pfbs->hwndToolbar, &rc);
  704.     yPos = (rc.bottom - rc.top + 1 - cyButton) / 2 + 1;
  705.  
  706.     // Let's make the comboboxes dropdown about 5 times the height
  707.     cyList = 5 * cyButton;
  708.  
  709.     // Get the font to use for the comboboxes
  710.     hfont = (HFONT) SendMessage(pfbs->hwndToolbar, WM_GETFONT, 0, 0);
  711.  
  712.     // Now create the other format bar controls
  713.  
  714.     // The name
  715.     xPos = 8;
  716.     pfbs->hwndName = CreateWindow(szComboBox, NULL,
  717.                                     WS_CHILD | WS_VSCROLL | CBS_DROPDOWN |
  718.                                     CBS_SORT | CBS_HASSTRINGS | WS_VISIBLE,
  719.                                     xPos, yPos, cxName, cyList,
  720.                                     pfbs->hwndToolbar, (HMENU) TBI_Name,
  721.                                     hinst, NULL);
  722.     if (!pfbs->hwndName)
  723.         goto ErrorNoName;
  724.     SetWindowFont(pfbs->hwndName, hfont, TRUE);
  725.     xPos += cxName + 8;
  726.  
  727.  
  728.     // The Size
  729.     pfbs->hwndSize = CreateWindow(szComboBox, NULL,
  730.                                     WS_CHILD | WS_VSCROLL | CBS_DROPDOWN |
  731.                                     WS_VISIBLE,
  732.                                     xPos, yPos, cxSize, cyList,
  733.                                     pfbs->hwndToolbar, (HMENU) TBI_Size,
  734.                                     hinst, NULL);
  735.     if (!pfbs->hwndSize)
  736.         goto ErrorNoSize;
  737.     SetWindowFont(pfbs->hwndSize, hfont, TRUE);
  738.  
  739.     // The color
  740.     //$ REVIEW: Magic number
  741.     SendMessage(pfbs->hwndToolbar, TB_GETITEMRECT, 3, (LPARAM) &rc);
  742.     pfbs->hwndColor = CreateWindow(szComboBox, NULL,
  743.                                     WS_CHILD | WS_VSCROLL | CBS_DROPDOWNLIST |
  744.                                     CBS_OWNERDRAWFIXED | WS_VISIBLE,
  745.                                     rc.right, yPos - 1, cxColor, cyList,
  746.                                     pfbs->hwndToolbar, (HMENU) TBI_Color,
  747.                                     hinst, NULL);
  748.     if (!pfbs->hwndColor)
  749.         goto ErrorNoColor;
  750.     SetWindowFont(pfbs->hwndColor, hfont, TRUE);
  751.  
  752.     // Set the initial color to black so it won't be redrawn.
  753.     pfbs->cf.dwMask |= INITIAL_COLOR;
  754.  
  755.     // Subclass the comboboxes' edit controls
  756.  
  757.     // Do the name first
  758.     hwndT = ChildWindowFromPoint(pfbs->hwndName, pt);
  759.     pfnWndProcT = (WNDPROC) SetWindowLong(hwndT, GWL_WNDPROC,
  760.                                                 (LONG) LFBEditWndProc);
  761.  
  762.     // If we don't know what the global EditWndProc is, save it
  763.     if (!pfnEditWndProc)
  764.         pfnEditWndProc = pfnWndProcT;
  765.  
  766.     // Next the size
  767.     hwndT = ChildWindowFromPoint(pfbs->hwndSize, pt);
  768.     (WNDPROC) SetWindowLong(hwndT, GWL_WNDPROC, (LONG) LFBEditWndProc);
  769.     
  770.     // Lastly the color
  771.     pfnWndProcT = (WNDPROC) SetWindowLong(pfbs->hwndColor, GWL_WNDPROC,
  772.                                                 (LONG) LFBComboBoxWndProc);
  773.  
  774.     // If we don't know what the global ComboBoxWndProc is, save it
  775.     if (!pfnComboBoxWndProc)
  776.         pfnComboBoxWndProc = pfnWndProcT;
  777.     
  778.     // Create a copy of the DC that the user gave up to play with
  779.     if(pcs->lpCreateParams)
  780.     {
  781.         HDC *    phdc = (HDC *) pcs->lpCreateParams;
  782.  
  783.         pfbs->hdc = CreateCompatibleDC(*phdc);
  784.     }
  785.     else
  786.     {
  787.         HDC hdc = GetDC(pcs->hwndParent);
  788.  
  789.         pfbs->hdc = CreateCompatibleDC(hdc);
  790.         ReleaseDC(pcs->hwndParent, hdc);
  791.     }
  792.  
  793.     if (!pfbs->hdc)
  794.         goto ErrorNoColor;
  795.     
  796.     // Get the number of pixels per inch vertically so we can do point sizes
  797.     pfbs->cyPerInch = GetDeviceCaps(pfbs->hdc, LOGPIXELSY);
  798.  
  799.     // Load up the names of the fonts and colors
  800.     FillNames(hwnd);
  801.     FillColors(hwnd);
  802.     // Continue creating
  803.     return TRUE;
  804.  
  805. ErrorNoColor:
  806.     DestroyWindow(pfbs->hwndSize);
  807.     pfbs->hwndSize = NULL;
  808.  
  809. ErrorNoSize:
  810.     DestroyWindow(pfbs->hwndName);
  811.     pfbs->hwndName = NULL;
  812.  
  813. ErrorNoName:
  814.     DestroyWindow(pfbs->hwndToolbar);
  815.     pfbs->hwndToolbar = NULL;
  816.  
  817. ErrorNoToolbar:
  818.     if (pfbs)
  819.         GlobalFreePtr(pfbs);
  820.  
  821. ErrorNoState:
  822.     return FALSE;
  823. }
  824.  
  825.  
  826. /*
  827.  *    FB_OnMeasureItem
  828.  *
  829.  *    Purpose:
  830.  *        We want to draw our own colors for the colors combobox
  831.  *
  832.  *    Arguments:
  833.  *        hwnd        The window
  834.  *        pmis        Pointer to a MEASUREITEMSTRUCT to be filled out
  835.  *
  836.  *    Returns:
  837.  *        None.
  838.  */
  839. LOCAL void FB_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT * pmis)
  840. {
  841.     switch (pmis->CtlID)
  842.     {
  843.     case TBI_Color:
  844.         pmis->itemWidth = 128;
  845.         pmis->itemHeight = 16;
  846.         break;
  847.     default:
  848.         TraceError("Don't know anything about CtlID", -1);
  849.         break;
  850.     }
  851. }
  852.  
  853.  
  854. /*
  855.  *    FB_OnDrawItem
  856.  *
  857.  *    Purpose:
  858.  *        We want to drawn our own colors for our color combobox
  859.  *
  860.  *    Arguments:
  861.  *        hwnd        The window
  862.  *        pdis        Pointer to a DRAWITEMSTRUCT to be filled out
  863.  *
  864.  *    Returns:
  865.  *        None.
  866.  */
  867. LOCAL void FB_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT * pdis)
  868. {
  869.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  870.     HDC                    hdc = pdis->hDC;
  871.     RECT                rc;
  872.     HBRUSH                hbrush;
  873.     COLORREF            cr = (COLORREF) pdis->itemData;
  874.     INT                    nIter = 2;
  875.  
  876.     // As far as we know we have only one owner drawn control
  877.     AssertSz(pdis->CtlType == ODT_COMBOBOX, "Know only comboboxes");
  878.     if (pdis->CtlID != TBI_Color)
  879.         return;
  880.  
  881.     // NULL object wanted ?
  882.     if (pdis->itemData == -1)
  883.         goto HandleFocus;
  884.  
  885.     switch (pdis->itemAction)
  886.     {
  887.     case ODA_DRAWENTIRE:
  888.         rc = pdis->rcItem;
  889.         InflateRect(&rc, -3, -3);
  890.         hbrush = CreateSolidBrush((COLORREF)cr);
  891.         FillRect(hdc, &rc, hbrush);
  892.         DeleteObject(hbrush);
  893.         FrameRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
  894.  
  895.         // *** FALL THROUGH ***
  896.  
  897.     case ODA_SELECT:
  898.         rc = pdis->rcItem;
  899.         if (pdis->itemState & ODS_SELECTED)
  900.             hbrush = pfbs->hbrushHighlight;
  901.         else
  902.             hbrush = pfbs->hbrushWindow;
  903.         while (nIter--)
  904.         {
  905.             InflateRect(&rc, -1, -1);
  906.             FrameRect(hdc, &rc, hbrush);
  907.         }
  908.  
  909.         if (pdis->itemAction != ODA_DRAWENTIRE)
  910.             break;
  911.  
  912.         // *** FALL THROUGH ***
  913.  
  914. HandleFocus:
  915.     case ODA_FOCUS:
  916.         if (pdis->itemState & ODS_FOCUS)
  917.             hbrush = pfbs->hbrushHighlight;
  918.         else
  919.             hbrush = pdis->itemData == -1 ? pfbs->hbrushButtonFace :
  920.                                             pfbs->hbrushWindow;
  921.         FrameRect(hdc, &pdis->rcItem, hbrush);
  922.         break;
  923.     }
  924.  
  925. }
  926.  
  927.  
  928. /*
  929.  *    PaintName
  930.  *
  931.  *    Purpose:
  932.  *        Paint the current name
  933.  *
  934.  *    Arguments:
  935.  *        pfbs        The current format bar state
  936.  *
  937.  *    Returns:
  938.  *        None.
  939.  */
  940. LOCAL VOID PaintName(FormatBarState * pfbs)
  941. {
  942.     LONG    ilFound;
  943.  
  944.     TraceCharFormat("PaintName", &pfbs->cf);
  945.     if (pfbs->cf.dwMask & CFM_FACE)
  946.     {
  947.         ilFound = SendMessage(pfbs->hwndName, CB_FINDSTRING, 0,
  948.                                 (LPARAM) pfbs->cf.szFaceName);
  949.         SendMessage(pfbs->hwndName, CB_SETCURSEL, (WPARAM) ilFound, 0);
  950.         if (ilFound == CB_ERR)
  951.             SetWindowText(pfbs->hwndName, pfbs->cf.szFaceName);
  952.     }
  953.     else
  954.         SetWindowText(pfbs->hwndName, TEXT(""));
  955.  
  956. }
  957.  
  958.  
  959. /*
  960.  *    PaintSize
  961.  *
  962.  *    Purpose:
  963.  *        Paint the current size
  964.  *
  965.  *    Arguments:
  966.  *        pfbs        The current format bar state
  967.  *
  968.  *    Returns:
  969.  *        None.
  970.  */
  971. LOCAL VOID PaintSize(FormatBarState * pfbs)
  972. {
  973.     LONG    lSize = MulDiv((INT) pfbs->cf.yHeight, 72, 1440);
  974.     LONG    ilFound;
  975.     TCHAR    szT[10];
  976.  
  977.     TraceCharFormat("PaintSize", &pfbs->cf);
  978.     szT[0] = 0;
  979.     if (lSize > 0 && (pfbs->cf.dwMask & CFM_SIZE))
  980.         wsprintf(szT, "%ld", lSize);
  981.     ilFound = SendMessage(pfbs->hwndSize, CB_FINDSTRINGEXACT, 0,
  982.                             (LPARAM) szT);
  983.     SendMessage(pfbs->hwndSize, CB_SETCURSEL, (WPARAM) ilFound, 0);
  984.     SetWindowText(pfbs->hwndSize, szT);
  985. }
  986.  
  987.  
  988. /*
  989.  *    PaintColor
  990.  *
  991.  *    Purpose:
  992.  *        Paint the current color
  993.  *
  994.  *    Arguments:
  995.  *        pfbs        The current format bar state
  996.  *
  997.  *    Returns:
  998.  *        None.
  999.  */
  1000. LOCAL VOID PaintColor(FormatBarState * pfbs)
  1001. {
  1002.     LONG        ilFound = -1;
  1003.     COLORREF    crTextColor = pfbs->cf.crTextColor;
  1004.  
  1005.     //$ FUTURE: Handle autocolor
  1006.  
  1007.     // If color isn't known, choose white
  1008.     TraceCharFormat("PaintColor", &pfbs->cf);
  1009.     if (pfbs->cf.dwMask & CFM_COLOR)
  1010.     {
  1011.         ilFound = SendMessage(pfbs->hwndColor, CB_FINDSTRINGEXACT, 0,
  1012.                                 (LPARAM) crTextColor);
  1013.         if (ilFound < 0)
  1014.         {
  1015.             // Not found, add a new color
  1016.             ilFound = SendMessage(pfbs->hwndColor, CB_ADDSTRING, 0,
  1017.                                 (LPARAM) crTextColor);
  1018.         }
  1019.     }
  1020.     SendMessage(pfbs->hwndColor, CB_SETCURSEL, (WPARAM) ilFound, 0);
  1021. }
  1022.  
  1023.  
  1024. /*
  1025.  *    PaintEffects
  1026.  *
  1027.  *    Purpose:
  1028.  *        Paint the current effects
  1029.  *
  1030.  *    Arguments:
  1031.  *        pfbs        The current format bar state
  1032.  *
  1033.  *    Returns:
  1034.  *        None.
  1035.  */
  1036. LOCAL VOID PaintEffects(FormatBarState * pfbs)
  1037. {
  1038.     HWND    hwndToolbar = pfbs->hwndToolbar;
  1039.     DWORD    dwMask = pfbs->cf.dwMask;
  1040.     DWORD    dwEffects = pfbs->cf.dwEffects;
  1041.     BOOL    fEffect;
  1042.     BOOL    fMask;
  1043.     INT        nID;
  1044.  
  1045.     TraceCharFormat("PaintEffects", &pfbs->cf);
  1046.     for (nID = TBI_Bold; nID <= TBI_Underline; nID++)
  1047.     {
  1048.         fMask = dwMask & rgdwCFEffect[nID - TBI_Bold] ? TRUE : FALSE;
  1049.         fEffect = dwEffects & rgdwCFEffect[nID - TBI_Bold] ? TRUE : FALSE;
  1050. #ifdef LIKE_WORD2
  1051.         // Act like Word
  1052.         SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(fEffect, 0));
  1053.         SendMessage(hwndToolbar, TB_INDETERMINATE, nID, MAKELONG(!fMask, 0));
  1054. #elif defined(LIKE_T3)
  1055.         // Act like T3
  1056.         SendMessage(hwndToolbar, TB_CHECKBUTTON, nID,
  1057.                     MAKELONG(fEffect && fMask, 0));
  1058. #else
  1059.         //$ Raid 2375: Show the user what is actually going to happen
  1060.         SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(fEffect, 0));
  1061. #endif
  1062.     }
  1063.  
  1064. }
  1065.  
  1066.  
  1067. /*
  1068.  *    PaintAlignment
  1069.  *
  1070.  *    Purpose:
  1071.  *        Paint the current alignment
  1072.  *
  1073.  *    Arguments:
  1074.  *        pfbs        The current format bar state
  1075.  *
  1076.  *    Returns:
  1077.  *        None.
  1078.  */
  1079. LOCAL VOID PaintAlignment(FormatBarState * pfbs)
  1080. {
  1081.     HWND    hwndToolbar = pfbs->hwndToolbar;
  1082.     DWORD    wAlignment = pfbs->pf.wAlignment;
  1083.     INT        nID;
  1084.  
  1085.     if (pfbs->pf.dwMask & PFM_ALIGNMENT)
  1086.     {
  1087. #ifdef LIKE_WORD
  1088.         // Make all the buttons active
  1089.         for (nID = TBI_Left; nID <= TBI_Right; nID++)
  1090.             SendMessage(hwndToolbar, TB_INDETERMINATE, nID,
  1091.                         MAKELONG(FALSE, 0));
  1092. #endif
  1093.         // And press down one of them
  1094.         switch (wAlignment)
  1095.         {
  1096.         case PFA_CENTER:
  1097.             nID = TBI_Center;
  1098.             break;
  1099.  
  1100.         case PFA_RIGHT:
  1101.             nID = TBI_Right;
  1102.             break;
  1103.  
  1104.         case PFA_LEFT:
  1105.         default:
  1106.             nID = TBI_Left;
  1107.             break;
  1108.         }
  1109.         SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(TRUE, 0));
  1110.     }
  1111.     else
  1112.     {
  1113. #ifdef LIKE_WORD
  1114.         // Make all the buttons indeterminate
  1115.         for (nID = TBI_Left; nID <= TBI_Right; nID++)
  1116.             SendMessage(hwndToolbar, TB_INDETERMINATE, nID, MAKELONG(TRUE, 0));
  1117. #else
  1118.         // Pop all the buttons
  1119.         for (nID = TBI_Left; nID <= TBI_Right; nID++)
  1120.             SendMessage(hwndToolbar, TB_CHECKBUTTON, nID, MAKELONG(FALSE, 0));
  1121. #endif
  1122.     }
  1123. }
  1124.  
  1125.  
  1126. /*
  1127.  *    FB_OnCommand
  1128.  *
  1129.  *    Purpose:
  1130.  *        Handle some of the notifications
  1131.  *
  1132.  *    Arguments:
  1133.  *        hwnd        The window
  1134.  *        pdis        Pointer to a DRAWITEMSTRUCT to be filled out
  1135.  *
  1136.  *    Returns:
  1137.  *        None.
  1138.  */
  1139. LOCAL void FB_OnCommand(HWND hwnd, INT nID, HWND hwndCtl, INT nNotify)
  1140. {
  1141.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  1142.     LONG                iSel;
  1143.     if (nNotify == CBN_ERRSPACE)
  1144.     {
  1145.         //$ FUTURE: Handle error out of space
  1146.         return;
  1147.     }
  1148.  
  1149.     switch (nNotify)
  1150.     {
  1151.     case CBN_SELENDOK:
  1152.         // Flag the next combobox message as somethng we want
  1153.         pfbs->fExpectChoice = TRUE;
  1154.         pfbs->fGiveUpFocus = TRUE;
  1155.         return;
  1156.  
  1157.     case 0:
  1158.         // This is a button from the toolbar if hwndCtl == pfbs->hwndToolbar
  1159.         if (hwndCtl != pfbs->hwndToolbar)
  1160.             return;
  1161.         break;
  1162.  
  1163.     case CBN_KILLFOCUS:
  1164.         switch (nID)
  1165.         {
  1166.         case TBI_Name:
  1167.             PaintName(pfbs);
  1168.             break;
  1169.  
  1170.         case TBI_Size:
  1171.             PaintSize(pfbs);
  1172.             break;
  1173.  
  1174.         case TBI_Color:
  1175.             PaintColor(pfbs);
  1176.             break;
  1177.         }
  1178.         return;
  1179.  
  1180.     case CBN_SELCHANGE:
  1181.         // The user is making up his mind so ignore the sel change
  1182.         if (!pfbs->fExpectChoice)
  1183.             return;
  1184.         break;
  1185.  
  1186.     case CBN_DROPDOWN:
  1187.         if (nID == TBI_Size)
  1188.             FFillSizes(hwnd);
  1189.         return;
  1190.  
  1191.     //$ REVIEW: Just check for fExpectChoice to shorten this switch ?
  1192.  
  1193.     // Throw away these notifications from the toolbar
  1194.     case TBN_BEGINDRAG:
  1195.     case TBN_ENDDRAG:
  1196.  
  1197.     // Throw away these notifications from the comboboxes
  1198.     case CBN_SETFOCUS:
  1199.     case CBN_CLOSEUP:
  1200.     case CBN_SELENDCANCEL:
  1201.     case CBN_EDITCHANGE:
  1202.     case CBN_EDITUPDATE:
  1203.     case CBN_DBLCLK:
  1204.  
  1205.     default:
  1206.         return;
  1207.     }
  1208.  
  1209.     switch (nID)
  1210.     {
  1211.     case TBI_Name:
  1212.         if (pfbs->fExpectChoice)
  1213.         {
  1214.             DWORD    dw;
  1215.  
  1216.             // Get the new font name
  1217.             pfbs->cf.dwMask |= CFM_FACE | CFM_CHARSET;
  1218.             pfbs->dwCFMaskChange = CFM_FACE | CFM_CHARSET;
  1219.  
  1220.             // Get the new selection
  1221.             iSel = SendMessage(pfbs->hwndName, CB_GETCURSEL, 0, 0);
  1222.             if (iSel < 0)
  1223.             {
  1224.         //DebugStr("\pBefore GetWindowText in Frmtbar.c");
  1225.                 GetWindowText(pfbs->hwndName, pfbs->cf.szFaceName,
  1226.                             sizeof(pfbs->cf.szFaceName) / sizeof(TCHAR));
  1227.                 pfbs->cf.bPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  1228.                 pfbs->cf.bCharSet = DEFAULT_CHARSET;
  1229.             }
  1230.             else
  1231.             {
  1232.                 SendMessage(pfbs->hwndName, CB_GETLBTEXT, (WPARAM) iSel,
  1233.                             (LPARAM) pfbs->cf.szFaceName);
  1234.  
  1235.                 // Pull the other bits of data we had packed away.
  1236.                 dw = ComboBox_GetItemData(pfbs->hwndName, iSel);
  1237.                 dw >>= 16;
  1238.                 pfbs->cf.bPitchAndFamily = (BYTE) dw & 0xFF;
  1239.                 dw >>= 8;
  1240.                 pfbs->cf.bCharSet = (BYTE) dw & 0xFF;
  1241.             }
  1242.  
  1243.             // Update the list of font sizes
  1244.             FFillSizes(hwnd);
  1245.             pfbs->fExpectChoice = FALSE;
  1246.         }
  1247.         break;
  1248.  
  1249.     case TBI_Size:
  1250.         if (pfbs->fExpectChoice)
  1251.         {
  1252.             TCHAR    szT[10];
  1253.             TCHAR *    pch = szT;
  1254.             LONG    lSize = 0;
  1255.  
  1256.             // Get the new font size
  1257.             pfbs->cf.dwMask |= CFM_SIZE;
  1258.             pfbs->dwCFMaskChange = CFM_SIZE;
  1259.             szT[0] = 0;
  1260.  
  1261.             // Get the new selection
  1262.             iSel = SendMessage(pfbs->hwndSize, CB_GETCURSEL, 0, 0);
  1263.             if (iSel < 0)
  1264.             {
  1265.     //    DebugStr("\pBefore GetWindowText in Format.c2");
  1266.                 GetWindowText(pfbs->hwndSize, szT, sizeof(szT) / sizeof(TCHAR));
  1267.             }
  1268.             else
  1269.                 SendMessage(pfbs->hwndSize, CB_GETLBTEXT, (WPARAM) iSel,
  1270.                             (LPARAM) szT);
  1271.  
  1272.             while (*pch)
  1273.             {
  1274.                 if (TEXT('0') <= *pch && *pch <= TEXT('9'))
  1275.                 {
  1276.                     lSize *= 10;
  1277.                     lSize += *pch - '0';
  1278.                 }
  1279.                 else
  1280.                 {
  1281.                     // Got a bad character, reject the user's input
  1282.                     lSize = 0;
  1283.                     break;
  1284.                 }
  1285.                 *pch++;
  1286.             }
  1287.  
  1288.             if (lSize > 0 && lSize <= yHeightCharPtsMost)
  1289.                 pfbs->cf.yHeight = lSize * 20;        // Make twips
  1290.             else
  1291.                 MessageBox(hwnd, "Size must be between 1 and 1638", "Font",
  1292.                             MB_ICONINFORMATION | MB_OK);
  1293.             pfbs->fExpectChoice = FALSE;
  1294.         }
  1295.         break;
  1296.  
  1297.     case TBI_Color:
  1298.         if (pfbs->fExpectChoice)
  1299.         {
  1300.             LONG ilSel = SendMessage(pfbs->hwndColor, CB_GETCURSEL, 0, 0);
  1301.  
  1302.             // Remember that we are picking a color
  1303.             pfbs->cf.dwMask |= CFM_COLOR;
  1304.             pfbs->dwCFMaskChange = CFM_COLOR;
  1305.  
  1306.             //$ FUTURE: For now always turn-off autocolor, but later we'll
  1307.             //            have to handle picking autocolor
  1308.             pfbs->cf.dwEffects &= ~CFE_AUTOCOLOR;
  1309.  
  1310.             if (ilSel < 0)
  1311.                 pfbs->cf.crTextColor = 0;
  1312.             else
  1313.                 pfbs->cf.crTextColor = (COLORREF) SendMessage(pfbs->hwndColor,
  1314.                                             CB_GETITEMDATA, (WPARAM) ilSel, 0);
  1315.             pfbs->fExpectChoice = FALSE;
  1316.         }
  1317.         break;
  1318.  
  1319.     case TBI_Bold:
  1320.     case TBI_Italic:
  1321.     case TBI_Underline:
  1322.     
  1323.         // NOTE: We reverse the if condition because by the time we get the
  1324.         //         notification, the button has already been pressed.
  1325.         pfbs->dwCFMaskChange = rgdwCFEffect[nID - TBI_Bold];
  1326.         pfbs->cf.dwMask |= rgdwCFEffect[nID - TBI_Bold];
  1327. #ifdef NEVER
  1328.         if (!SendMessage(pfbs->hwndToolbar, TB_ISBUTTONCHECKED, nID, 0))
  1329.             pfbs->cf.dwEffects &= ~rgdwCFEffect[nID - TBI_Bold];
  1330.         else
  1331.             pfbs->cf.dwEffects |= rgdwCFEffect[nID - TBI_Bold];
  1332. #else
  1333.         pfbs->cf.dwEffects ^= rgdwCFEffect[nID - TBI_Bold];
  1334. #endif
  1335.         pfbs->fGiveUpFocus = TRUE;
  1336.         break;
  1337.  
  1338.     case TBI_Bullet:
  1339.         // NOTE: The button has already been pushed,
  1340.         // so the checked state is accurate
  1341.         pfbs->pf.dwMask |= PFM_NUMBERING | PFM_OFFSET;
  1342.         if (SendMessage(pfbs->hwndToolbar, TB_ISBUTTONCHECKED, nID, 0))
  1343.         {
  1344.             pfbs->pf.wNumbering = PFN_BULLET;
  1345.             pfbs->pf.dxOffset = cxBulletIndent;
  1346.         }
  1347.         else
  1348.         {
  1349.             pfbs->pf.wNumbering = 0;
  1350.             pfbs->pf.dxOffset = 0;
  1351.         }
  1352.         pfbs->fGiveUpFocus = TRUE;
  1353.         break;
  1354.  
  1355.     case TBI_IncreaseIndent:
  1356.     case TBI_DecreaseIndent:
  1357.         pfbs->fGiveUpFocus = TRUE;
  1358.         break;
  1359.  
  1360.     case TBI_Left:
  1361.     case TBI_Center:
  1362.     case TBI_Right:
  1363.         pfbs->pf.dwMask |= PFM_ALIGNMENT;
  1364.         pfbs->pf.wAlignment = rgwPFAlignment[nID - TBI_Left];
  1365.         pfbs->fGiveUpFocus = TRUE;
  1366.         PaintAlignment(pfbs);
  1367.         break;
  1368.  
  1369.  
  1370.  
  1371.     }
  1372.  
  1373.  
  1374.  
  1375.     // Give up the focus ?
  1376.     if (pfbs->fGiveUpFocus)
  1377.     {
  1378.         pfbs->fGiveUpFocus = FALSE;
  1379.         SetFocus(hwnd);
  1380.     }
  1381.  
  1382.     // Go tell our parent
  1383.     SendMessage(GetParent(hwnd), WM_COMMAND,
  1384.                 GET_WM_COMMAND_MPS(nID, hwndCtl, nNotify));
  1385. }
  1386.  
  1387.  
  1388. /*
  1389.  *    FB_OnPaint
  1390.  *
  1391.  *    Purpose:
  1392.  *        Update our screen
  1393.  *
  1394.  *    Arguments:
  1395.  *        hwnd        The window
  1396.  *
  1397.  *    Returns:
  1398.  *        None.
  1399.  */
  1400. LOCAL void FB_OnPaint(HWND hwnd)
  1401. {
  1402.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  1403.     PAINTSTRUCT            ps;
  1404.  
  1405.     // Repaint the toolbar as needed
  1406.     BeginPaint(hwnd, &ps);
  1407. //    PaintName(pfbs);
  1408. //    PaintSize(pfbs);
  1409. //    PaintColor(pfbs);
  1410. //    PaintEffects(pfbs);
  1411. //    PaintAlignment(pfbs);
  1412.     SendMessage(pfbs->hwndToolbar, WM_PAINT, 0, 0);
  1413.     EndPaint(hwnd, &ps);
  1414. }
  1415.  
  1416.  
  1417. /*
  1418.  *    SetCharFormat
  1419.  *
  1420.  *    Purpose:
  1421.  *        Set the current char format
  1422.  *
  1423.  *    Arguments:
  1424.  *        hwnd        The format bar window
  1425.  *        pcfNew        The new formatting
  1426.  *
  1427.  *    Returns:
  1428.  *        None.
  1429.  */
  1430. LOCAL VOID SetCharFormat(HWND hwnd, CHARFORMAT *pcfNew)
  1431. {
  1432.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  1433.     CHARFORMAT *        pcf = &pfbs->cf;
  1434.     DWORD                dwMask;
  1435.     DWORD                dwEffects;
  1436.  
  1437.     TraceCharFormat("EM_SETCHARFORMAT", pcfNew);
  1438.  
  1439.     if(pcfNew->cbSize != sizeof(CHARFORMAT))
  1440.         return;
  1441.  
  1442.     // Change in font name ?
  1443.     if (lstrcmpi(pcf->szFaceName, pcfNew->szFaceName) ||
  1444.         (pcf->bPitchAndFamily != pcfNew->bPitchAndFamily) ||
  1445.         (pcf->dwMask & CFM_FACE) != (pcfNew->dwMask & CFM_FACE))
  1446.     {
  1447.         pcf->dwMask &= ~CFM_FACE;
  1448.         pcf->dwMask |= pcfNew->dwMask & CFM_FACE;
  1449.         lstrcpy(pcf->szFaceName, pcfNew->szFaceName);
  1450.         pcf->bPitchAndFamily = pcfNew->bPitchAndFamily;
  1451.         PaintName(pfbs);
  1452.     }
  1453.  
  1454.     // Change in charset ?
  1455.     if (pcf->bCharSet != pcfNew->bCharSet ||
  1456.         (pcf->dwMask & CFM_CHARSET) != (pcfNew->dwMask & CFM_CHARSET))
  1457.     {
  1458.         pcf->dwMask &= ~CFM_CHARSET;
  1459.         pcf->dwMask |= pcfNew->dwMask & CFM_CHARSET;
  1460.         pcf->bCharSet = pcfNew->bCharSet;
  1461.         PaintSize(pfbs);
  1462.     }
  1463.  
  1464.     // Change in font size ?
  1465.     if (pcf->yHeight != pcfNew->yHeight ||
  1466.         (pcf->dwMask & CFM_SIZE) != (pcfNew->dwMask & CFM_SIZE))
  1467.     {
  1468.         pcf->dwMask &= ~CFM_SIZE;
  1469.         pcf->dwMask |= pcfNew->dwMask & CFM_SIZE;
  1470.         pcf->yHeight = pcfNew->yHeight;
  1471.         PaintSize(pfbs);
  1472.     }
  1473.  
  1474.     // Change in font color ?
  1475.     if (pcf->crTextColor != pcfNew->crTextColor ||
  1476.         (pcf->dwMask & CFM_COLOR) != (pcfNew->dwMask & CFM_COLOR))
  1477.     {        
  1478.         pcf->dwMask &= ~CFM_COLOR;
  1479.         pcf->dwMask |= pcfNew->dwMask & CFM_COLOR;
  1480.         pcf->crTextColor = pcfNew->crTextColor;
  1481.         PaintColor(pfbs);
  1482.     }
  1483.  
  1484.     // Change in effects ?
  1485.     dwMask = pcf->dwMask & CFM_MASKS;
  1486.     dwEffects = pcf->dwEffects & CFE_EFFECTS;
  1487.     if (((pcfNew->dwMask & CFM_MASKS) != dwMask) ||
  1488.         ((pcfNew->dwEffects & CFE_EFFECTS) != dwEffects))
  1489.     {
  1490.         pcf->dwMask &= ~CFM_MASKS;
  1491.         pcf->dwMask |= pcfNew->dwMask & CFM_MASKS;
  1492.         pcf->dwEffects = pcfNew->dwEffects & CFE_EFFECTS;
  1493.         PaintEffects(pfbs);
  1494.     }
  1495. }
  1496.  
  1497.  
  1498. /*
  1499.  *    SetParaFormat
  1500.  *
  1501.  *    Purpose:
  1502.  *        Set the current char format
  1503.  *
  1504.  *    Arguments:
  1505.  *        hwnd        The format bar window
  1506.  *        ppfNew        The new formatting
  1507.  *
  1508.  *    Returns:
  1509.  *        None.
  1510.  */
  1511. LOCAL VOID SetParaFormat(HWND hwnd, PARAFORMAT *ppfNew)
  1512. {
  1513.     FormatBarState *    pfbs = PfbsGetWindowPtr(hwnd);
  1514.     PARAFORMAT *        ppf = &pfbs->pf;
  1515.     DWORD                dwMaskOld = ppf->dwMask;
  1516.     BOOL                fChanged = FALSE;
  1517.  
  1518.     // update the mask for tri-state sake
  1519.     ppf->dwMask = (ppf->dwMask & ~(PFM_NUMBERING | PFM_ALIGNMENT)) |
  1520.         (ppfNew->dwMask & (PFM_NUMBERING | PFM_ALIGNMENT));
  1521.  
  1522.     // Change in numbering ?
  1523.     if (ppf->wNumbering != ppfNew->wNumbering)
  1524.     {
  1525.         const BOOL fBulleted = ppfNew->wNumbering == PFN_BULLET;
  1526.  
  1527.         ppf->wNumbering = ppfNew->wNumbering;
  1528.         SendMessage(pfbs->hwndToolbar, TB_CHECKBUTTON, TBI_Bullet, MAKELONG(fBulleted, 0));
  1529.     }
  1530.  
  1531.     // Change in alignment ?
  1532.     if (ppf->wAlignment != ppfNew->wAlignment)
  1533.     {
  1534.         ppf->wAlignment = ppfNew->wAlignment;
  1535.         fChanged |= TRUE;
  1536.     }
  1537.  
  1538.     if (fChanged || dwMaskOld != ppf->dwMask)
  1539.         PaintAlignment(pfbs);
  1540. }
  1541.  
  1542.  
  1543. /*
  1544.  *    LFormatBarWndProc
  1545.  *
  1546.  *    Purpose:
  1547.  *        Take care of handling the notifications from the combobox controls we
  1548.  *        get from the format bar
  1549.  *
  1550.  *    Arguments:
  1551.  *        hwnd
  1552.  *        wMsg
  1553.  *        wParam
  1554.  *        lParam
  1555.  *
  1556.  *    Returns:
  1557.  *        LRESULT
  1558.  */
  1559. LRESULT CALLBACK LFormatBarWndProc(HWND hwnd, UINT wMsg, WPARAM wParam,
  1560.                                     LPARAM lParam)
  1561. {
  1562.     FormatBarState *pfbs = PfbsGetWindowPtr(hwnd);
  1563.     BOOL fShift;
  1564.  
  1565.     switch(wMsg)
  1566.     {
  1567.     HANDLE_MSG(hwnd, WM_MEASUREITEM, FB_OnMeasureItem);
  1568.  
  1569.     case WM_COMMAND:
  1570.         FB_OnCommand(hwnd, GET_WM_COMMAND_ID(wParam, lParam),
  1571.                      GET_WM_COMMAND_HWND(wParam, lParam),
  1572.                      GET_WM_COMMAND_CMD(wParam, lParam));
  1573.         return 0;
  1574.  
  1575.     case WM_NCCREATE:
  1576.         return FB_OnNcCreate(hwnd, (CREATESTRUCT *) lParam);
  1577.  
  1578.  
  1579.     case WM_DRAWITEM:
  1580.         FB_OnDrawItem(hwnd, (DRAWITEMSTRUCT *) lParam);
  1581.         return TRUE;
  1582.  
  1583.     case WM_PAINT:
  1584.         FB_OnPaint(hwnd);
  1585.         break;
  1586.  
  1587.     case WM_DESTROY:
  1588.         if (pfbs)
  1589.         {
  1590.             if (pfbs->hwndName)
  1591.                 DestroyWindow(pfbs->hwndName);
  1592.             if (pfbs->hwndSize)
  1593.                 DestroyWindow(pfbs->hwndSize);
  1594.             if (pfbs->hwndColor)
  1595.                 DestroyWindow(pfbs->hwndColor);
  1596.             if (pfbs->hwndToolbar)
  1597.                 DestroyWindow(pfbs->hwndToolbar);
  1598.             if (pfbs->hbrushWindow)
  1599.                 DeleteObject(pfbs->hbrushWindow);
  1600.             if (pfbs->hbrushHighlight)
  1601.                 DeleteObject(pfbs->hbrushHighlight);
  1602.             if (pfbs->hbrushButtonFace)
  1603.                 DeleteObject(pfbs->hbrushButtonFace);
  1604.             if (pfbs->hdc)
  1605.                 DeleteDC(pfbs->hdc);
  1606.             GlobalFreePtr(pfbs);
  1607.             SetWindowPtr(hwnd, NULL);
  1608.         }
  1609.         break;
  1610.  
  1611.     case WM_SHOWWINDOW:
  1612.         if (pfbs)
  1613.         {
  1614.             INT    nCmd =    wParam ? SW_SHOW : SW_HIDE;
  1615.  
  1616.             ShowWindow(pfbs->hwndToolbar, nCmd);
  1617.             SendMessage(pfbs->hwndToolbar, WM_SIZE, 0, 0);
  1618.             ShowWindow(pfbs->hwndName, nCmd);
  1619.             ShowWindow(pfbs->hwndSize, nCmd);
  1620.             ShowWindow(pfbs->hwndColor, nCmd);
  1621.         }
  1622.         return 0;
  1623.  
  1624.     case WM_SIZE:
  1625.         if (pfbs)
  1626.         {
  1627.             RECT    rcMe;
  1628.             RECT    rcParent;
  1629.  
  1630.             // Get our current dimensions
  1631.             GetClientRect(pfbs->hwndToolbar, &rcMe);
  1632.             rcMe.bottom += 3;
  1633.  
  1634.             // We want to fit our parent's width
  1635.             GetClientRect(GetParent(hwnd), &rcParent);
  1636.  
  1637.             // Make it so
  1638.             SetWindowPos(hwnd, HWND_TOP, 0, 0, rcParent.right - rcParent.left,
  1639.                         rcMe.bottom - rcMe.top, SWP_NOMOVE | SWP_NOZORDER);
  1640.         }
  1641.         return 0;
  1642.  
  1643.     case WM_ENABLE:
  1644.         if (pfbs)
  1645.         {
  1646.             INT    nID;
  1647.  
  1648.             EnableWindow(pfbs->hwndToolbar, wParam);
  1649.             EnableWindow(pfbs->hwndName, wParam);
  1650.             EnableWindow(pfbs->hwndSize, wParam);
  1651.             EnableWindow(pfbs->hwndColor, wParam);
  1652.             for (nID = TBI_Bold; nID <= TBI_Right; nID++)
  1653.                 SendMessage(pfbs->hwndToolbar, TB_ENABLEBUTTON, nID,
  1654.                             MAKELONG(wParam, 0));
  1655.         }
  1656.         break;
  1657.  
  1658.     case WM_SYSCOLORCHANGE:
  1659.         // Update our concept of the brushes
  1660.         if (pfbs)
  1661.             UpdateBrushes(hwnd);
  1662.         break;
  1663.  
  1664.     case EM_GETPARAFORMAT:
  1665.         Assert(lParam);
  1666.         if (lParam)
  1667.         {
  1668.             PARAFORMAT * const ppf = (PARAFORMAT *) lParam;
  1669.  
  1670.             if(ppf->cbSize == sizeof(PARAFORMAT))
  1671.             {
  1672.                 CopyMemory(((LPBYTE) ppf) + sizeof(ppf->cbSize),
  1673.                     ((LPBYTE) &pfbs->pf) + sizeof(ppf->cbSize),
  1674.                     sizeof(PARAFORMAT) - sizeof(ppf->cbSize));
  1675.             }
  1676.         }
  1677.         return 0;
  1678.  
  1679.     case EM_SETPARAFORMAT:
  1680.         Assert(lParam);
  1681.         if (lParam)
  1682.             SetParaFormat(hwnd, (PARAFORMAT *) lParam);
  1683.         return TRUE;
  1684.  
  1685.     case EM_GETCHARFORMAT:
  1686.         Assert(lParam);
  1687.         if (lParam)
  1688.         {
  1689.             CHARFORMAT * const pcf = (CHARFORMAT *) lParam;
  1690.  
  1691.             if(pcf->cbSize == sizeof(CHARFORMAT))
  1692.             {
  1693.                 CopyMemory(((LPBYTE) pcf) + sizeof(pcf->cbSize),
  1694.                     ((LPBYTE) &pfbs->cf) + sizeof(pcf->cbSize),
  1695.                     sizeof(CHARFORMAT) - sizeof(pcf->cbSize));
  1696.                 pcf->dwMask &= pfbs->dwCFMaskChange;
  1697.                 TraceCharFormat("EM_GETCHARFORMAT", pcf);
  1698.             }
  1699.         }
  1700.         return 0;
  1701.  
  1702.     case EM_SETCHARFORMAT:
  1703.         Assert(lParam);
  1704.         if (lParam)
  1705.             SetCharFormat(hwnd, (CHARFORMAT *) lParam);
  1706.         return TRUE;
  1707.  
  1708.     case WM_RETURN:
  1709.         // The user made a choice
  1710.         pfbs->fExpectChoice = TRUE;
  1711.         pfbs->fGiveUpFocus = TRUE;
  1712.         FB_OnCommand(hwnd, wParam, (HWND) lParam, CBN_SELCHANGE);
  1713.         return 0;
  1714.  
  1715.     case WM_TAB:
  1716.         // Only change the choice if TAB was pressed on a closed dropdown
  1717.         pfbs->fExpectChoice = !SendMessage((HWND) lParam, CB_GETDROPPEDSTATE,
  1718.                                             0, 0);
  1719.         FB_OnCommand(hwnd, wParam, (HWND) lParam, CBN_SELCHANGE);
  1720.  
  1721.         // Change focus, FB_OnCommand will take care of copying changed data
  1722.         fShift = GetKeyState(VK_SHIFT) & 0x8000 ? TRUE : FALSE;
  1723.         switch (wParam)
  1724.         {
  1725.         case TBI_Name:
  1726.             SetFocus(fShift ? pfbs->hwndColor : pfbs->hwndSize);
  1727.             break;
  1728.  
  1729.         case TBI_Size:
  1730.             SetFocus(fShift ? pfbs->hwndName : pfbs->hwndColor);
  1731.             break;
  1732.  
  1733.         case TBI_Color:
  1734.             SetFocus(fShift ? pfbs->hwndSize : pfbs->hwndName);
  1735.             break;
  1736.         }
  1737.         return 0;
  1738.  
  1739.     case WM_ESCAPE:
  1740.         SetFocus(hwnd);
  1741.         FB_OnPaint(hwnd);
  1742.         return 0;
  1743.     }
  1744.  
  1745.     return DefWindowProc(hwnd, wMsg, wParam, lParam);
  1746. }
  1747.  
  1748.  
  1749. /*
  1750.  *    FInitFormatBarClass()
  1751.  *
  1752.  *    Purpose:
  1753.  *        Superclasses the toolbar so that we get support for a format bar
  1754.  *
  1755.  *    Arguments:
  1756.  *        hinst        This instance
  1757.  *
  1758.  *    Returns:
  1759.  *        TRUE if class is successfully initialized.
  1760.  */
  1761. BOOL FInitFormatBarClass(HINSTANCE hinst)
  1762. {
  1763.     WNDCLASS wc;
  1764.  
  1765.     // Are format bars registered yet ?
  1766.     if (!GetClassInfo(hinst, szFormatBar, &wc))
  1767.     {
  1768.         wc.style = CS_HREDRAW | CS_VREDRAW;
  1769.         wc.lpfnWndProc = LFormatBarWndProc;
  1770.         wc.cbClsExtra = 0;
  1771.         wc.cbWndExtra = sizeof(FormatBarState *);
  1772.         wc.hInstance = hinst;
  1773.         wc.hIcon = NULL;
  1774.         wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  1775.         wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  1776.         wc.lpszMenuName = NULL;
  1777.         wc.lpszClassName = szFormatBar;
  1778.     
  1779.         if (!RegisterClass(&wc))
  1780.         {
  1781.             TraceError("FInitFormatBarClass: Couldn't register", -1);
  1782.             return FALSE;
  1783.         }
  1784.     }
  1785.     return TRUE;
  1786. }
  1787.  
  1788.  
  1789. /*
  1790.  *    FCreateFormatBar
  1791.  *
  1792.  *    Purpose:
  1793.  *        Creates a format bar
  1794.  *
  1795.  *    Arguments:
  1796.  *        hwndParent        The parent of this format bar
  1797.  *        wID                The control ID to be associated with this format bar
  1798.  *        hdc                A device context that we can copy so we can do various
  1799.  *                        font information functions
  1800.  *
  1801.  *    Returns:
  1802.  *        The window handle of the format bar
  1803.  */
  1804. HWND HwndCreateFormatBar(HWND hwndParent, WORD wID, HDC hdc)
  1805. {
  1806.     HWND        hwndFormatBar = NULL;
  1807.     HINSTANCE    hinst = (HINSTANCE) GetWindowLong(hwndParent, GWL_HINSTANCE);
  1808.     RECT        rc;
  1809.  
  1810.     // Initialize the format bar class
  1811.     //$ REVIEW: Move into WinMain or LibMain
  1812.     if (!FInitFormatBarClass(hinst))
  1813.     {
  1814.         TraceError("HwndCreateFormatBar: Not registered", -1);
  1815.         return NULL;
  1816.     }
  1817.  
  1818.     // Create the main toolbar
  1819.     GetClientRect(hwndParent, &rc);
  1820.     hwndFormatBar = CreateWindow(szFormatBar, NULL, WS_CHILD | WS_VISIBLE,
  1821.                                     0, 0, rc.right - rc.left, 29,
  1822.                                     hwndParent, (HMENU) wID, hinst,
  1823.                                     (LPVOID) (hdc ? &hdc : NULL));
  1824.     if (!hwndFormatBar)
  1825.     {
  1826.         TraceError("HwndCreateFormatBar: Can't create", -1);
  1827.         goto Error;
  1828.     }
  1829.  
  1830.     // Return a pointer to our state information
  1831.     return hwndFormatBar;
  1832.     
  1833. Error:
  1834.     return NULL;
  1835. }
  1836.