We concluded last time that we wanted the custom large font to apply only to the columns containing Chinese characters and leave the original font in place for the English columns. We do this by carrying two fonts around, choosing the appropriate one for each column.

class RootWindow : public Window
{
 ...
private:
 HWND m_hwndLV;
 HWND m_hwndEdit;
 HWND m_hwndLastFocus;
 HFONT m_hfChinese;
 HFONT m_hfNormal;
 int  m_cyEdit;
 ...
}

RootWindow::RootWindow()
 : m_hfChinese(NULL)
 , m_hfNormal(NULL)
{
}

RootWindow::~RootWindow()
{
 if (m_hfChinese) DeleteObject(m_hfChinese);
 if (m_hfNormal) DeleteObject(m_hfNormal);
}

LRESULT RootWindow::OnCreate()
{
 ...
 ListView_SetExtendedListViewStyleEx(m_hwndLV,
                                     LVS_EX_FULLROWSELECT,
                                     LVS_EX_FULLROWSELECT);

 LOGFONT lf;
 if (!GetObject(GetWindowFont(m_hwndLV), sizeof(lf), &lf)) {
  return -1;
 }
 m_hfNormal = CreateFontIndirect(&lf);
 if (!m_hfNormal) return -1;
 lf.lfHeight += lf.lfHeight / 2; // 50% bigger
 m_hfChinese = CreateFontIndirect(&lf);
 if (!m_hfChinese) return -1;
 SetWindowFont(m_hwndLV, m_hfChinese, FALSE);
 ...
}

Before we change the default font for the list view to the Chinese font, we create a copy of the original font (which we rather presumptuously call "normal") for safekeeping. Next, when the list view asks us to customize a column, we select the appropriate font and return the "I also changed the font" code.

LRESULT RootWindow::OnLVCustomDraw(NMLVCUSTOMDRAW* pcd)
{
 ...
 case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
  pcd->clrText = m_clrTextNormal;
  if (pcd->iSubItem == COL_SIMP &&
    pcd->nmcd.dwItemSpec < (DWORD)Length()) {
    const DictionaryEntry& de = Item(pcd->nmcd.dwItemSpec);
    if (de.m_pszSimp) {
      pcd->clrText = RGB(0x80, 0x00, 0x00);
    }
  }
  // break;
  if (pcd->iSubItem == COL_TRAD || pcd->iSubItem == COL_SIMP) {
    SelectFont(pcd->nmcd.hdc, m_hfChinese);
  } else {
    SelectFont(pcd->nmcd.hdc, m_hfNormal);
  }
  return CDRF_NEWFONT;
 ...
}

There are several important details here.

First, we set the Chinese font as the "overall" font for the list view. It would have been easier for us not to do this; after all, since we explicitly set the font for each column, why does it matter what the default font is? It also would have removed the need to create a copy of the original font. But if you delete the SetWindowFont(m_hwndLV, m_hfChinese); line, the bottoms of the Chinese characters get cut off. The reason is that the list view uses the default font to decide what the line spacing should be. Therefore, the default font for the list view needs to be the largest font we intend to use for any column.

Why does the list view use the default font to decide on the line spacing? Because it's not clairevoyant. That's the only font it has, after all. It doesn't know what font you're going to select in your CDDS_ITEMPREPAINT | CDDS_SUBITEM notification handler. All it has is the font you set with SetWindowFont.

Another important detail is that once we have decided to use different fonts for different columns, we are committed to selecting a font for all columns. The reason for this was discussed when we discussed how to colorize the columns.

Finally, there is the important detail of returning the CDRF_NEWFONT value when we change the font. For performance reasons, the list view assumes you aren't changing the font on a subitem-by-subitem basis (since very few list views do) and it caches many font properties to avoid having to recalculate them all the time. Returning CDRF_NEWFONT indicates that the list view should look at the font you selected and base its computations on that font instead.

Since boldface, italics and underline are font attributes, you can use this "select a custom font" technique to make selected items display as boldface, italics, or underline, in addition to using it to change the font size as we did here.

That's all for this month. Next month will be a rather boring one, adding a status bar to make the Chinese characters even more readable. After that, we'll enhance the dictionary lookup algorithm, which is itself groundwork for dynamic translation, as I may have alluded to in a previous entry.

[Raymond is currently away; this message was pre-recorded.]