I added a feature to my ABC program that it turns out I never actually used: Change the font. I added this in case my nieces were somehow unhappy with the font I chose, and this was a little escape hatch to let me select a different one.

The real work happens in the Choose­Font function. All I have to do is call it.

#include <commdlg.h>

void ChangeFont(HWND hwnd)
{
  LOGFONT lf;
  GetObject(g_hfEdit, sizeof(lf), &lf);
  CHOOSEFONT cf = { sizeof(cf) };
  cf.hwndOwner = hwnd;
  cf.lpLogFont = &lf;
  cf.Flags = CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
  if (ChooseFont(&cf)) {
    HFONT hfNew = CreateFontIndirect(&lf);
    if (hfNew) {
      DeleteObject(g_hfEdit);
      g_hfEdit = hfNew;
      SetWindowFont(g_hwndChild, g_hfEdit, TRUE);
    }
  }
}

I tell the common font dialog to initialize itself from the LOGFONT I passed in, which I initialize from the font itself. If the user picks a font, the Choose­Font function puts the result in the same LOGFONT, and I use that to create the new font and swap it into the edit control.

The rest is just hooking up this function.

void OnCommand(HWND hwnd, int id, HWND hwndCtl, UINT codeNotify)
{
  switch (id) {
  case 1:
    ChangeFont(hwnd);
    break;
 }
}

    HANDLE_MSG(hwnd, WM_COMMAND, OnCommand);

We hook up a WM_COMMAND handler which responds to command number 1 by changing the font.

Now to hook up the command to a secret hotkey: Ctrl+F.

// scratch.rc
1 ACCELERATORS
BEGIN
 "F", 1, VIRTKEY, NOINVERT, CONTROL
END

// scratch.cpp

...
    ShowWindow(hwnd, nShowCmd);

    HACCEL hacc = LoadAccelerators(hinst, MAKEINTRESOURCE(1));
    while (GetMessage(&msg, NULL, 0, 0)) {
      if (!TranslateAccelerator(hwnd, hacc, &msg)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
    DestroyAcceleratorTable(hacc);
...

There we go, now we can change the font on the fly. Like I said, this was a feature I added pre-emptively, and it turns out I never needed it.

Next time, we'll look at changes inspired by actual usability issues.