// ------------------------------------------------------------------
// Windows 2000 Graphics API Black Book
// Chapter 4 - Listing 4.2 (Font Enumeration Demo)
//
// Created by Damon Chandler <dmc27@ee.cornell.edu>
// Updates can be downloaded at: <www.coriolis.com>
//
// Please do not hesistate to e-mail me at dmc27@ee.cornell.edu
// if you have any questions about this code.
// ------------------------------------------------------------------


//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include <windows.h>
#include <cassert>


#ifndef SNDMSG
#define SNDMSG ::SendMessage
#endif /* ifndef SNDMSG */


//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<


HWND hListBox = NULL;
const int ID_LISTBOX = 101;

HINSTANCE hInst;
const char* WndClassName = "GMainWnd";
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
   LPARAM lParam);


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE, LPTSTR,
   int nCmdShow)
{
   hInst = hInstance;

   WNDCLASS wc;
   memset(&wc, 0, sizeof(WNDCLASS));

   wc.style = CS_VREDRAW | CS_HREDRAW;
   wc.lpszClassName = WndClassName;
   wc.lpfnWndProc = MainWndProc;
   wc.hInstance = hInstance;
   wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground = reinterpret_cast<HBRUSH>(
      COLOR_BTNFACE + 1
      );

   if (RegisterClass(&wc))
   {
      HWND hWnd =
         CreateWindow(
            WndClassName, TEXT("Font Enumeration Demo"),
            WS_OVERLAPPED | WS_SYSMENU | WS_CAPTION |
            WS_VISIBLE | WS_CLIPCHILDREN,
            CW_USEDEFAULT, CW_USEDEFAULT, 295, 285,
            NULL, NULL, hInst, NULL
            );

      if (hWnd)
      {
         ShowWindow(hWnd, nCmdShow);
         UpdateWindow(hWnd);

         MSG msg;
         while (GetMessage(&msg, NULL, 0, 0))
         {
             TranslateMessage(&msg);
             DispatchMessage(&msg);
         }
      }
    }
    return 0;
}
//-------------------------------------------------------------------------


int CALLBACK MyEnumFontFamExProc(ENUMLOGFONTEX *lpelfe,
   NEWTEXTMETRICEX* lpntme, int FontType, LPARAM lParam)
{
   if (FontType == TRUETYPE_FONTTYPE)
   {
      // if the typeface name is not already in the list
      LPARAM name = reinterpret_cast<LPARAM>(lpelfe->elfFullName);
      if (SNDMSG(hListBox, LB_FINDSTRINGEXACT, (ULONG)-1, name) == LB_ERR)
      {
         // add each font to the list box
         int index = SNDMSG(hListBox, LB_ADDSTRING, 0, name);

         // fix the size of the font
         lpelfe->elfLogFont.lfHeight = -20;
         lpelfe->elfLogFont.lfWidth = 0;

         // create a new font and store its handle
         // as the data of the newly added item
         HFONT hFont = CreateFontIndirect(&lpelfe->elfLogFont);
         SNDMSG(hListBox, LB_SETITEMDATA, index,
                reinterpret_cast<LPARAM>(hFont));
      }
   }
   return TRUE;
}
//-------------------------------------------------------------------------


void AddScreenFonts()
{
   // grab a handle to the screen's DC
   HDC hScreenDC = GetDC(NULL);
   try
   {
      //
      // NOTE: Windows 95, 98 and Me requires that the lpLogfont
      // (second) parameter of the EnumFontFamiliesEx function is
      // non-NULL.  This parameter can be NULL on Windows NT/2000.
      //
      LOGFONT lf = {0};
      lf.lfCharSet = DEFAULT_CHARSET;

      // enumerate the current screen fonts
      EnumFontFamiliesEx(
         hScreenDC, &lf,
         (FONTENUMPROC)MyEnumFontFamExProc,
         0, 0
         );
   }
   catch (...)
   {
      // release the screen's DC
      ReleaseDC(NULL, hScreenDC);
   }
   // release the screen's DC
   ReleaseDC(NULL, hScreenDC);
}
//-------------------------------------------------------------------------


LRESULT CALLBACK MainWndProc(HWND hWnd, UINT msg, WPARAM wParam,
   LPARAM lParam)
{
   switch (msg)
   {
      case WM_CREATE:
      {
         hListBox =
            CreateWindowEx(
               WS_EX_CLIENTEDGE, TEXT("LISTBOX"), TEXT(""),
               WS_CHILD | WS_VISIBLE | LBS_STANDARD |
               LBS_HASSTRINGS | LBS_OWNERDRAWFIXED,
               20, 10, 250, 250,
               hWnd, reinterpret_cast<HMENU>(ID_LISTBOX),
               hInst, NULL
               );
         if (hListBox)
         {
            AddScreenFonts();
         }
      }
      case WM_MEASUREITEM:
      {
         // grab a pointer to the MEASUREITEMSTRUCT structure
         LPMEASUREITEMSTRUCT lpmis =
            reinterpret_cast<LPMEASUREITEMSTRUCT>(lParam);

         // test the identifier of the control that
         // the message is meant for
         if ((int)lpmis->CtlID == ID_LISTBOX)
         {
            // adjust the height
            lpmis->itemHeight = 25;

            return TRUE;
         }
         break;
      }
      case WM_DRAWITEM:
      {
         // grab a pointer to the DRAWITEMSTRUCT structure
         LPDRAWITEMSTRUCT lpdis =
            reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);

         // test the identifier of the control that
         // the message is meant for
         if ((int)lpdis->CtlID == ID_LISTBOX)
         {
            COLORREF OldColor = GetTextColor(lpdis->hDC);
            int stock = WHITE_BRUSH;

            // if the item is currently selected
            if (lpdis->itemState & ODS_SELECTED)
            {
               // set the text color to white and
               // the background color to black
               COLORREF clrWhite = PALETTERGB(255, 255, 255);
               OldColor = SetTextColor(lpdis->hDC, clrWhite);
               stock = BLACK_BRUSH;
            }
            FillRect(
               lpdis->hDC, &lpdis->rcItem,
               static_cast<HBRUSH>(GetStockObject(stock))
               );

            if ((int)lpdis->itemID != -1)
            {
               // extract the item's text
               char text[MAX_PATH];
               SNDMSG(hListBox, LB_GETTEXT, lpdis->itemID,
                      reinterpret_cast<LPARAM>(text));

               // extract the corresponding font handle
               DWORD value =
                   SNDMSG(hListBox, LB_GETITEMDATA, lpdis->itemID, 0);
               HFONT hFont = reinterpret_cast<HFONT>(value);

               // select the corresponding font
               // into the device context
               HFONT HOldFont = static_cast<HFONT>(
                  SelectObject(lpdis->hDC, hFont)
                  );

               // render the text transparently
               SetBkMode(lpdis->hDC, TRANSPARENT);

               // render the text
               RECT RText = lpdis->rcItem;
               InflateRect(&RText, -2, -2);
               DrawText(lpdis->hDC, text, strlen(text), &RText,
                        DT_LEFT | DT_VCENTER | DT_SINGLELINE);

               // restore the previous font
               SelectObject(lpdis->hDC, HOldFont);
            }

            // render the focus rectangle
            if (lpdis->itemState & ODS_FOCUS)
            {
               DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
            }

            // restore the previous color/mode
            SetTextColor(lpdis->hDC, OldColor);
            SetBkMode(lpdis->hDC, OPAQUE);

            return TRUE;
         }
         break;
      }
      case WM_DESTROY:
      {
         // delete each created font object
         int count = SNDMSG(hListBox, LB_GETCOUNT, 0, 0);
         for (int index = 0; index < count; ++index)
         {
            DWORD value = SNDMSG(hListBox, LB_GETITEMDATA, index, 0);
            DeleteObject(reinterpret_cast<HFONT>(value));
         }

         PostQuitMessage(0);
         break;
      }
   }
   return DefWindowProc(hWnd, msg, wParam, lParam);
}
//-------------------------------------------------------------------------